[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# Local build files\n*c.cmd\n*a.exe\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\n[Xx]64/\n[Xx]86/\n[Bb]uild/\nbld/\n[Bb]in/\n[Oo]bj/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n\n# Visual Studio Code\n.vscode/\n\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n\n# TODO: Un-comment the next line if you do not want to checkin \n# your web deploy settings because they may include unencrypted\n# passwords\n#*.pubxml\n*.publishproj\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Microsoft Azure ApplicationInsights config file\nApplicationInsights.config\n\n# Windows Store app package directory\nAppPackages/\nBundleArtifacts/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# LightSwitch generated files\nGeneratedArtifacts/\nModelManifest.xml\n\n# Paket dependency manager\n.paket/paket.exe\n\n# FAKE - F# Make\n.fake/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\n\n# ubuntu 14.04 version\nsudo: required\ndist: trusty\n\nmatrix:\n  include:\n    - os: linux\n      compiler: gcc\n      addons:\n        apt:\n          sources: ['ubuntu-toolchain-r-test']\n          packages: ['g++-5']\n      env:\n        - MATRIX_EVAL=\"CC=gcc-5 && CXX=g++-5\"\n\n    - os: linux\n      compiler: gcc\n      addons:\n        apt:\n          sources: ['ubuntu-toolchain-r-test']\n          packages: ['g++-6']\n      env:\n        - MATRIX_EVAL=\"CC=gcc-6 && CXX=g++-6\"\n\n    - os: linux\n      compiler: gcc\n      addons:\n        apt:\n          sources: ['ubuntu-toolchain-r-test']\n          packages: ['g++-7']\n      env:\n        - MATRIX_EVAL=\"CC=gcc-7 && CXX=g++-7\"\n        \n    - os: osx\n      osx_image: xcode5\n      env:\n        - MATRIX_EVAL=\"CC=clang && CXX=clang++\"\n        \n    - os: osx\n      osx_image: xcode6\n      env:\n        - MATRIX_EVAL=\"CC=clang && CXX=clang++\"\n        \n    - os: osx\n      osx_image: xcode7\n      env:\n        - MATRIX_EVAL=\"CC=clang && CXX=clang++\"\n        \n    - os: osx\n      osx_image: xcode8\n      env:\n        - MATRIX_EVAL=\"CC=clang && CXX=clang++\"\n        \n        \nbefore_script:\n  - eval \"${MATRIX_EVAL}\"\n  - $CXX --version\n  \nscript:\n  - mkdir build && cd ./build\n  - cmake ..\n  - make\n  - cd ../bin && ./stltest\n  \nbranches:\n  only:\n  - master\n  \nnotifications:\n  email: false\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8)\n\nproject(MyTinySTL)\n\n# version\nset(MyTinySTL_VERSION_MAJOR 2)\nset(MyTinySTL_VERSION_MINOR 0)\nset(MyTinySTL_VERSION_PATCH 0)\nset(MyTinySTL_VERSION \"${MyTinySTL_VERSION_MAJOR}.${MyTinySTL_VERSION_MINOR}.${MyTinySTL_VERSION_PATCH}\")\nmessage(STATUS \"The version of this project is: ${MyTinySTL_VERSION}\")\n\n# build type\nset(CMAKE_BUILD_TYPE release)\n\nif (\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"GNU\")\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Wno-sign-compare -Wno-unused-but-set-variable -Wno-array-bounds\")\n\t# set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion)\n\tif (CMAKE_CXX_COMPILER_VERSION VERSION_LESS \"5.0.0\")\n\t\tmessage(FATAL_ERROR \"required GCC 5.0 or later\")\n\telse()\n\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\n\tendif()\nelseif (CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Wno-sign-compare\")\n\t# set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough)\n\tif (CMAKE_CXX_COMPILER_VERSION VERSION_LESS \"3.5.0\")\n\t\tmessage(FATAL_ERROR \"required Clang 3.5 or later\")\n\telse()\n\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\n\tendif()\nendif()\n\nmessage(STATUS \"The cmake_cxx_flags is: ${CMAKE_CXX_FLAGS}\")\n\nadd_subdirectory(${PROJECT_SOURCE_DIR}/Test)\n"
  },
  {
    "path": "License.txt",
    "content": "Copyright (c) 2016-2017 Alinshans. All rights reserved.\r\n\r\nFirst published on github, see https://github.com/Alinshans/MyTinySTL\r\n\r\nThe MyTinySTL source code is licensed under the MIT License.\r\n\r\nPermission 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:\r\n\r\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n\r\nTHE 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.\r\n"
  },
  {
    "path": "MSVC/MyTinySTL_VS2015.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 14\nVisualStudioVersion = 14.0.25420.1\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"MyTinySTL\", \"MyTinySTL_VS2015.vcxproj\", \"{E88807F6-B07C-4371-BD38-FB1569F894E4}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x64.Build.0 = Debug|x64\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x86.Build.0 = Debug|Win32\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x64.ActiveCfg = Release|x64\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x64.Build.0 = Release|x64\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x86.ActiveCfg = Release|Win32\n\t\t{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "MSVC/MyTinySTL_VS2015.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{E88807F6-B07C-4371-BD38-FB1569F894E4}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>MyTinySTL</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n    <ProjectName>MyTinySTL</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\Test\\algorithm_performance_test.h\" />\n    <ClInclude Include=\"..\\Test\\algorithm_test.h\" />\n    <ClInclude Include=\"..\\Test\\deque_test.h\" />\n    <ClInclude Include=\"..\\Test\\Lib\\redbud\\io\\color.h\" />\n    <ClInclude Include=\"..\\Test\\Lib\\redbud\\platform.h\" />\n    <ClInclude Include=\"..\\Test\\list_test.h\" />\n    <ClInclude Include=\"..\\Test\\map_test.h\" />\n    <ClInclude Include=\"..\\Test\\queue_test.h\" />\n    <ClInclude Include=\"..\\Test\\set_test.h\" />\n    <ClInclude Include=\"..\\Test\\stack_test.h\" />\n    <ClInclude Include=\"..\\Test\\string_test.h\" />\n    <ClInclude Include=\"..\\Test\\test.h\" />\n    <ClInclude Include=\"..\\Test\\unordered_map_test.h\" />\n    <ClInclude Include=\"..\\Test\\unordered_set_test.h\" />\n    <ClInclude Include=\"..\\Test\\vector_test.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\algo.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\algobase.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\algorithm.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\alloc.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\allocator.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\basic_string.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\construct.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\deque.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\exceptdef.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\functional.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\hashtable.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\unordered_map.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\unordered_set.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\heap_algo.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\iterator.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\list.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\map.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\memory.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\numeric.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\queue.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\rb_tree.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\set.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\set_algo.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\stack.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\astring.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\type_traits.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\uninitialized.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\util.h\" />\n    <ClInclude Include=\"..\\MyTinySTL\\vector.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\Test\\test.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "MSVC/MyTinySTL_VS2015.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"资源文件\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"include\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"source\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"test\">\n      <UniqueIdentifier>{ec314ff3-dcde-4cac-a63a-4f6827750d0a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"test\\Lib\">\n      <UniqueIdentifier>{c6f24d77-e6f0-439e-954a-c0ca577689d5}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\MyTinySTL\\type_traits.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\construct.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\alloc.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\allocator.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\uninitialized.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\iterator.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\numeric.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\algobase.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\heap_algo.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\set_algo.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\algo.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\algorithm.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\vector.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\memory.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\list.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\deque.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\stack.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\queue.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\functional.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\rb_tree.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\set.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\map.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\hashtable.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\basic_string.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\unordered_set.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\unordered_map.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\algorithm_performance_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\algorithm_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\deque_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\list_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\map_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\queue_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\set_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\stack_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\string_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\unordered_map_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\unordered_set_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\vector_test.h\">\n      <Filter>test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\Lib\\redbud\\platform.h\">\n      <Filter>test\\Lib</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\Test\\Lib\\redbud\\io\\color.h\">\n      <Filter>test\\Lib</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\astring.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\util.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\MyTinySTL\\exceptdef.h\">\n      <Filter>include</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\Test\\test.cpp\">\n      <Filter>test</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "MyTinySTL/algo.h",
    "content": "﻿#ifndef MYTINYSTL_ALGO_H_\n#define MYTINYSTL_ALGO_H_\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4244)\n#endif\n\n// 这个头文件包含了 mystl 的一系列算法\n\n#include <cstddef>\n#include <ctime>\n\n#include \"algobase.h\"\n#include \"memory.h\"\n#include \"heap_algo.h\"\n#include \"functional.h\"\n\nnamespace mystl\n{\n\n/*****************************************************************************************/\n// all_of\n// 检查[first, last)内是否全部元素都满足一元操作 unary_pred 为 true 的情况，满足则返回 true\n/*****************************************************************************************/\ntemplate <class InputIter, class UnaryPredicate>\nbool all_of(InputIter first, InputIter last, UnaryPredicate unary_pred)\n{\n  for (; first != last; ++first)\n  {\n    if (!unary_pred(*first))\n      return false;\n  }\n  return true;\n}\n\n/*****************************************************************************************/\n// any_of\n// 检查[first, last)内是否存在某个元素满足一元操作 unary_pred 为 true 的情况，满足则返回 true\n/*****************************************************************************************/\ntemplate <class InputIter, class UnaryPredicate>\nbool any_of(InputIter first, InputIter last, UnaryPredicate unary_pred)\n{\n  for (; first != last; ++first)\n  {\n    if (unary_pred(*first))\n      return true;\n  }\n  return false;\n}\n\n/*****************************************************************************************/\n// none_of\n// 检查[first, last)内是否全部元素都不满足一元操作 unary_pred 为 true 的情况，满足则返回 true\n/*****************************************************************************************/\ntemplate <class InputIter, class UnaryPredicate>\nbool none_of(InputIter first, InputIter last, UnaryPredicate unary_pred)\n{\n  for (; first != last; ++first)\n  {\n    if (unary_pred(*first))\n      return false;\n  }\n  return true;\n}\n\n/*****************************************************************************************/\n// count\n// 对[first, last)区间内的元素与给定值进行比较，缺省使用 operator==，返回元素相等的个数\n/*****************************************************************************************/\ntemplate <class InputIter, class T>\nsize_t count(InputIter first, InputIter last, const T& value)\n{\n  size_t n = 0;\n  for (; first != last; ++first)\n  {\n    if (*first == value)\n      ++n;\n  }\n  return n;\n}\n\n/*****************************************************************************************/\n// count_if\n// 对[first, last)区间内的每个元素都进行一元 unary_pred 操作，返回结果为 true 的个数\n/*****************************************************************************************/\ntemplate <class InputIter, class UnaryPredicate>\nsize_t count_if(InputIter first, InputIter last, UnaryPredicate unary_pred)\n{\n  size_t n = 0;\n  for (; first != last; ++first)\n  {\n    if (unary_pred(*first))\n      ++n;\n  }\n  return n;\n}\n\n/*****************************************************************************************/\n// find\n// 在[first, last)区间内找到等于 value 的元素，返回指向该元素的迭代器\n/*****************************************************************************************/\ntemplate <class InputIter, class T>\nInputIter\nfind(InputIter first, InputIter last, const T& value)\n{\n  while (first != last && *first != value)\n    ++first;\n  return first;\n}\n\n/*****************************************************************************************/\n// find_if\n// 在[first, last)区间内找到第一个令一元操作 unary_pred 为 true 的元素并返回指向该元素的迭代器\n/*****************************************************************************************/\ntemplate <class InputIter, class UnaryPredicate>\nInputIter\nfind_if(InputIter first, InputIter last, UnaryPredicate unary_pred)\n{\n  while (first != last && !unary_pred(*first))\n    ++first;\n  return first;\n}\n\n/*****************************************************************************************/\n// find_if_not\n// 在[first, last)区间内找到第一个令一元操作 unary_pred 为 false 的元素并返回指向该元素的迭代器\n/*****************************************************************************************/\ntemplate <class InputIter, class UnaryPredicate>\nInputIter\nfind_if_not(InputIter first, InputIter last, UnaryPredicate unary_pred)\n{\n  while (first != last && unary_pred(*first))\n    ++first;\n  return first;\n}\n\n/*****************************************************************************************/\n// search\n// 在[first1, last1)中查找[first2, last2)的首次出现点\n/*****************************************************************************************/\ntemplate <class ForwardIter1, class ForwardIter2>\nForwardIter1\nsearch(ForwardIter1 first1, ForwardIter1 last1,\n       ForwardIter2 first2, ForwardIter2 last2)\n{\n  auto d1 = mystl::distance(first1, last1);\n  auto d2 = mystl::distance(first2, last2);\n  if (d1 < d2)\n    return last1;\n  auto current1 = first1;\n  auto current2 = first2;\n  while (current2 != last2)\n  {\n    if (*current1 == *current2)\n    {\n      ++current1;\n      ++current2;\n    }\n    else\n    {\n      if (d1 == d2)\n      {\n        return last1;\n      }\n      else\n      {\n        current1 = ++first1;\n        current2 = first2;\n        --d1;\n      }\n    }\n  }\n  return first1;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter1, class ForwardIter2, class Compared>\nForwardIter1\nsearch(ForwardIter1 first1, ForwardIter1 last1,\n       ForwardIter2 first2, ForwardIter2 last2, Compared comp)\n{\n  auto d1 = mystl::distance(first1, last1);\n  auto d2 = mystl::distance(first2, last2);\n  if (d1 < d2)\n    return last1;\n  auto current1 = first1;\n  auto current2 = first2;\n  while (current2 != last2)\n  {\n    if (comp(*current1, *current2))\n    {\n      ++current1;\n      ++current2;\n    }\n    else\n    {\n      if (d1 == d2)\n      {\n        return last1;\n      }\n      else\n      {\n        current1 = ++first1;\n        current2 = first2;\n        --d1;\n      }\n    }\n  }\n  return first1;\n}\n\n/*****************************************************************************************/\n// search_n\n// 在[first, last)中查找连续 n 个 value 所形成的子序列，返回一个迭代器指向该子序列的起始处\n/*****************************************************************************************/\ntemplate <class ForwardIter, class Size, class T>\nForwardIter\nsearch_n(ForwardIter first, ForwardIter last, Size n, const T& value)\n{\n  if (n <= 0)\n  {\n    return first;\n  }\n  else\n  {\n    first = mystl::find(first, last, value);\n    while (first != last)\n    {\n      auto m = n - 1;\n      auto i = first;\n      ++i;\n      while (i != last && m != 0 && *i == value)\n      {\n        ++i;\n        --m;\n      }\n      if (m == 0)\n      {\n        return first;\n      }\n      else\n      {\n        first = mystl::find(i, last, value);\n      }\n    }\n    return last;\n  }\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter, class Size, class T, class Compared>\nForwardIter\nsearch_n(ForwardIter first, ForwardIter last,\n         Size n, const T& value, Compared comp)\n{\n  if (n <= 0)\n  {\n    return first;\n  }\n  else\n  {\n    while (first != last)\n    {\n      if (comp(*first, value))\n        break;\n      ++first;\n    }\n    while (first != last)\n    {\n      auto m = n - 1;\n      auto i = first;\n      ++i;\n      while (i != last && m != 0 && comp(*i, value))\n      {\n        ++i;\n        --m;\n      }\n      if (m == 0)\n      {\n        return first;\n      }\n      else\n      {\n        while (i != last)\n        {\n          if (comp(*i, value))\n            break;\n          ++i;\n        }\n        first = i;\n      }\n    }\n    return last;\n  }\n}\n\n/*****************************************************************************************/\n// find_end\n// 在[first1, last1)区间中查找[first2, last2)最后一次出现的地方，若不存在返回 last1\n/*****************************************************************************************/\n// find_end_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter1, class ForwardIter2>\nForwardIter1\nfind_end_dispatch(ForwardIter1 first1, ForwardIter1 last1,\n                  ForwardIter2 first2, ForwardIter2 last2,\n                  forward_iterator_tag, forward_iterator_tag)\n{\n  if (first2 == last2)\n  {\n    return last1;\n  }\n  else\n  {\n    auto result = last1;\n    while (true)\n    {\n      // 利用 search 查找某个子序列的首次出现点，找不到则返回 last1\n      auto new_result = mystl::search(first1, last1, first2, last2);\n      if (new_result == last1)\n      {\n        return result;\n      }\n      else\n      {\n        result = new_result;\n        first1 = new_result;\n        ++first1;\n      }\n    }\n  }\n}\n\n// find_end_dispatch 的 bidirectional_iterator_tag 版本\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter1\nfind_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1,\n                  BidirectionalIter2 first2, BidirectionalIter2 last2,\n                  bidirectional_iterator_tag, bidirectional_iterator_tag)\n{\n  typedef reverse_iterator<BidirectionalIter1> reviter1;\n  typedef reverse_iterator<BidirectionalIter2> reviter2;\n  reviter1 rlast1(first1);\n  reviter2 rlast2(first2);\n  reviter1 rresult = mystl::search(reviter1(last1), rlast1, reviter2(last2), rlast2);\n  if (rresult == rlast1)\n  {\n    return last1;\n  }\n  else\n  {\n    auto result = rresult.base();\n    mystl::advance(result, -mystl::distance(first2, last2));\n    return result;\n  }\n}\n\ntemplate <class ForwardIter1, class ForwardIter2>\nForwardIter1\nfind_end(ForwardIter1 first1, ForwardIter1 last1,\n         ForwardIter2 first2, ForwardIter2 last2)\n{\n  typedef typename iterator_traits<ForwardIter1>::iterator_category Category1;\n  typedef typename iterator_traits<ForwardIter2>::iterator_category Category2;\n  return mystl::find_end_dispatch(first1, last1, first2, last2, Category1(), Category2());\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\n// find_end_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter1, class ForwardIter2, class Compared>\nForwardIter1\nfind_end_dispatch(ForwardIter1 first1, ForwardIter1 last1,\n                  ForwardIter2 first2, ForwardIter2 last2,\n                  forward_iterator_tag, forward_iterator_tag, Compared comp)\n{\n  if (first2 == last2)\n  {\n    return last1;\n  }\n  else\n  {\n    auto result = last1;\n    while (true)\n    {\n      // 利用 search 查找某个子序列的首次出现点，找不到则返回 last1\n      auto new_result = mystl::search(first1, last1, first2, last2, comp);\n      if (new_result == last1)\n      {\n        return result;\n      }\n      else\n      {\n        result = new_result;\n        first1 = new_result;\n        ++first1;\n      }\n    }\n  }\n}\n\n// find_end_dispatch 的 bidirectional_iterator_tag 版本\ntemplate <class BidirectionalIter1, class BidirectionalIter2, class Compared>\nBidirectionalIter1\nfind_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1,\n                  BidirectionalIter2 first2, BidirectionalIter2 last2,\n                  bidirectional_iterator_tag, bidirectional_iterator_tag, Compared comp)\n{\n  typedef reverse_iterator<BidirectionalIter1> reviter1;\n  typedef reverse_iterator<BidirectionalIter2> reviter2;\n  reviter1 rlast1(first1);\n  reviter2 rlast2(first2);\n  reviter1 rresult = mystl::search(reviter1(last1), rlast1, reviter2(last2), rlast2, comp);\n  if (rresult == rlast1)\n  {\n    return last1;\n  }\n  else\n  {\n    auto result = rresult.base();\n    mystl::advance(result, -mystl::distance(first2, last2));\n    return result;\n  }\n}\n\ntemplate <class ForwardIter1, class ForwardIter2, class Compared>\nForwardIter1\nfind_end(ForwardIter1 first1, ForwardIter1 last1,\n         ForwardIter2 first2, ForwardIter2 last2, Compared comp)\n{\n  typedef typename iterator_traits<ForwardIter1>::iterator_category Category1;\n  typedef typename iterator_traits<ForwardIter2>::iterator_category Category2;\n  return mystl::find_end_dispatch(first1, last1, first2, last2, Category1(), Category2(), comp);\n}\n\n/*****************************************************************************************/\n// find_first_of\n// 在[first1, last1)中查找[first2, last2)中的某些元素，返回指向第一次出现的元素的迭代器\n/*****************************************************************************************/\ntemplate <class InputIter, class ForwardIter>\nInputIter\nfind_first_of(InputIter first1, InputIter last1,\n              ForwardIter first2, ForwardIter last2)\n{\n  for (; first1 != last1; ++first1)\n  {\n    for (auto iter = first2; iter != last2; ++iter)\n    {\n      if (*first1 == *iter)\n        return first1;\n    }\n  }\n  return last1;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter, class ForwardIter, class Compared>\nInputIter\nfind_first_of(InputIter first1, InputIter last1,\n              ForwardIter first2, ForwardIter last2, Compared comp)\n{\n  for (; first1 != last1; ++first1)\n  {\n    for (auto iter = first2; iter != last2; ++iter)\n    {\n      if (comp(*first1, *iter))\n        return first1;\n    }\n  }\n  return last1;\n}\n\n/*****************************************************************************************/\n// for_each\n// 使用一个函数对象 f 对[first, last)区间内的每个元素执行一个 operator() 操作，但不能改变元素内容\n// f() 可返回一个值，但该值会被忽略\n/*****************************************************************************************/\ntemplate <class InputIter, class Function>\nFunction for_each(InputIter first, InputIter last, Function f)\n{\n  for (; first != last; ++first)\n  {\n    f(*first);\n  }\n  return f;\n}\n\n/*****************************************************************************************/\n// adjacent_find\n// 找出第一对匹配的相邻元素，缺省使用 operator== 比较，如果找到返回一个迭代器，指向这对元素的第一个元素\n/*****************************************************************************************/\ntemplate <class ForwardIter>\nForwardIter adjacent_find(ForwardIter first, ForwardIter last)\n{\n  if (first == last)  return last;\n  auto next = first;\n  while (++next != last)\n  {\n    if (*first == *next)  return first;\n    first = next;\n  }\n  return last;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter, class Compared>\nForwardIter adjacent_find(ForwardIter first, ForwardIter last, Compared comp)\n{\n  if (first == last)  return last;\n  auto next = first;\n  while (++next != last)\n  {\n    if (comp(*first, *next))  return first;\n    first = next;\n  }\n  return last;\n}\n\n/*****************************************************************************************/\n// lower_bound\n// 在[first, last)中查找第一个不小于 value 的元素，并返回指向它的迭代器，若没有则返回 last\n/*****************************************************************************************/\n// lbound_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter, class T>\nForwardIter\nlbound_dispatch(ForwardIter first, ForwardIter last,\n                const T& value, forward_iterator_tag)\n{\n  auto len = mystl::distance(first, last);\n  auto half = len;\n  ForwardIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first;\n    mystl::advance(middle, half);\n    if (*middle < value)\n    {\n      first = middle;\n      ++first;\n      len = len - half - 1;\n    }\n    else\n    {\n      len = half;\n    }\n  }\n  return first;\n}\n\n// lbound_dispatch 的 random_access_iterator_tag 版本\ntemplate <class RandomIter, class T>\nRandomIter\nlbound_dispatch(RandomIter first, RandomIter last,\n                const T& value, random_access_iterator_tag)\n{\n  auto len = last - first;\n  auto half = len;\n  RandomIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first + half;\n    if (*middle < value)\n    {\n      first = middle + 1;\n      len = len - half - 1;\n    }\n    else\n    {\n      len = half;\n    }\n  }\n  return first;\n}\n\ntemplate <class ForwardIter, class T>\nForwardIter\nlower_bound(ForwardIter first, ForwardIter last, const T& value)\n{\n  return mystl::lbound_dispatch(first, last, value, iterator_category(first));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\n// lbound_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter, class T, class Compared>\nForwardIter\nlbound_dispatch(ForwardIter first, ForwardIter last,\n                const T& value, forward_iterator_tag, Compared comp)\n{\n  auto len = mystl::distance(first, last);\n  auto half = len;\n  ForwardIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first;\n    mystl::advance(middle, half);\n    if (comp(*middle, value))\n    {\n      first = middle;\n      ++first;\n      len = len - half - 1;\n    }\n    else\n    {\n      len = half;\n    }\n  }\n  return first;\n}\n\n// lbound_dispatch 的 random_access_iterator_tag 版本\ntemplate <class RandomIter, class T, class Compared>\nRandomIter\nlbound_dispatch(RandomIter first, RandomIter last,\n                const T& value, random_access_iterator_tag, Compared comp)\n{\n  auto len = last - first;\n  auto half = len;\n  RandomIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first + half;\n    if (comp(*middle, value))\n    {\n      first = middle + 1;\n      len = len - half - 1;\n    }\n    else\n    {\n      len = half;\n    }\n  }\n  return first;\n}\n\ntemplate <class ForwardIter, class T, class Compared>\nForwardIter\nlower_bound(ForwardIter first, ForwardIter last, const T& value, Compared comp)\n{\n  return mystl::lbound_dispatch(first, last, value, iterator_category(first), comp);\n}\n\n/*****************************************************************************************/\n// upper_bound\n// 在[first, last)中查找第一个大于value 的元素，并返回指向它的迭代器，若没有则返回 last\n/*****************************************************************************************/\n// ubound_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter, class T>\nForwardIter\nubound_dispatch(ForwardIter first, ForwardIter last,\n                const T& value, forward_iterator_tag)\n{\n  auto len = mystl::distance(first, last);\n  auto half = len;\n  ForwardIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first;\n    mystl::advance(middle, half);\n    if (value < *middle)\n    {\n      len = half;\n    }\n    else\n    {\n      first = middle;\n      ++first;\n      len = len - half - 1;\n    }\n  }\n  return first;\n}\n\n// ubound_dispatch 的 random_access_iterator_tag 版本\ntemplate <class RandomIter, class T>\nRandomIter\nubound_dispatch(RandomIter first, RandomIter last,\n                const T& value, random_access_iterator_tag)\n{\n  auto len = last - first;\n  auto half = len;\n  RandomIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first + half;\n    if (value < *middle)\n    {\n      len = half;\n    }\n    else\n    {\n      first = middle + 1;\n      len = len - half - 1;\n    }\n  }\n  return first;\n}\n\ntemplate <class ForwardIter, class T>\nForwardIter\nupper_bound(ForwardIter first, ForwardIter last, const T& value)\n{\n  return mystl::ubound_dispatch(first, last, value, iterator_category(first));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\n// ubound_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter, class T, class Compared>\nForwardIter\nubound_dispatch(ForwardIter first, ForwardIter last,\n                const T& value, forward_iterator_tag, Compared comp)\n{\n  auto len = mystl::distance(first, last);\n  auto half = len;\n  ForwardIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first;\n    mystl::advance(middle, half);\n    if (comp(value, *middle))\n    {\n      len = half;\n    }\n    else\n    {\n      first = middle;\n      ++first;\n      len = len - half - 1;\n    }\n  }\n  return first;\n}\n\n// ubound_dispatch 的 random_access_iterator_tag 版本\ntemplate <class RandomIter, class T, class Compared>\nRandomIter\nubound_dispatch(RandomIter first, RandomIter last,\n                const T& value, random_access_iterator_tag, Compared comp)\n{\n  auto len = last - first;\n  auto half = len;\n  RandomIter middle;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first + half;\n    if (comp(value, *middle))\n    {\n      len = half;\n    }\n    else\n    {\n      first = middle + 1;\n      len = len - half - 1;\n    }\n  }\n  return first;\n}\n\ntemplate <class ForwardIter, class T, class Compared>\nForwardIter\nupper_bound(ForwardIter first, ForwardIter last, const T& value, Compared comp)\n{\n  return mystl::ubound_dispatch(first, last, value, iterator_category(first), comp);\n}\n\n/*****************************************************************************************/\n// binary_search\n// 二分查找，如果在[first, last)内有等同于 value 的元素，返回 true，否则返回 false\n/*****************************************************************************************/\ntemplate <class ForwardIter, class T>\nbool binary_search(ForwardIter first, ForwardIter last, const T& value)\n{\n  auto i = mystl::lower_bound(first, last, value);\n  return i != last && !(value < *i);\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter, class T, class Compared>\nbool binary_search(ForwardIter first, ForwardIter last, const T& value, Compared comp)\n{\n  auto i = mystl::lower_bound(first, last, value);\n  return i != last && !comp(value, *i);\n}\n\n/*****************************************************************************************/\n// equal_range\n// 查找[first,last)区间中与 value 相等的元素所形成的区间，返回一对迭代器指向区间首尾\n// 第一个迭代器指向第一个不小于 value 的元素，第二个迭代器指向第一个大于 value 的元素\n/*****************************************************************************************/\n// erange_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter, class T>\nmystl::pair<ForwardIter, ForwardIter>\nerange_dispatch(ForwardIter first, ForwardIter last,\n                const T& value, forward_iterator_tag)\n{\n  auto len = mystl::distance(first, last);\n  auto half = len;\n  ForwardIter middle, left, right;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first;\n    mystl::advance(middle, half);\n    if (*middle < value)\n    {\n      first = middle;\n      ++first;\n      len = len - half - 1;\n    }\n    else if (value < *middle)\n    {\n      len = half;\n    }\n    else\n    {\n      left = mystl::lower_bound(first, last, value);\n      mystl::advance(first, len);\n      right = mystl::upper_bound(++middle, first, value);\n      return mystl::pair<ForwardIter, ForwardIter>(left, right);\n    }\n  }\n  return mystl::pair<ForwardIter, ForwardIter>(last, last);\n}\n\n// erange_dispatch 的 random_access_iterator_tag 版本\ntemplate <class RandomIter, class T>\nmystl::pair<RandomIter, RandomIter>\nerange_dispatch(RandomIter first, RandomIter last,\n                const T& value, random_access_iterator_tag)\n{\n  auto len = last - first;\n  auto half = len;\n  RandomIter middle, left, right;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first + half;\n    if (*middle < value)\n    {\n      first = middle + 1;\n      len = len - half - 1;\n    }\n    else if (value < *middle)\n    {\n      len = half;\n    }\n    else\n    {\n      left = mystl::lower_bound(first, middle, value);\n      right = mystl::upper_bound(++middle, first + len, value);\n      return mystl::pair<RandomIter, RandomIter>(left, right);\n    }\n  }\n  return mystl::pair<RandomIter, RandomIter>(last, last);\n}\n\ntemplate <class ForwardIter, class T>\nmystl::pair<ForwardIter, ForwardIter>\nequal_range(ForwardIter first, ForwardIter last, const T& value)\n{\n  return mystl::erange_dispatch(first, last, value, iterator_category(first));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\n// erange_dispatch 的 forward iterator 版本\ntemplate <class ForwardIter, class T, class Compared>\nmystl::pair<ForwardIter, ForwardIter>\nerange_dispatch(ForwardIter first, ForwardIter last,\n                const T& value, forward_iterator_tag, Compared comp)\n{\n  auto len = mystl::distance(first, last);\n  auto half = len;\n  ForwardIter middle, left, right;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first;\n    mystl::advance(middle, half);\n    if (comp(*middle, value))\n    {\n      first = middle;\n      ++first;\n      len = len - half - 1;\n    }\n    else if (comp(value, *middle))\n    {\n      len = half;\n    }\n    else\n    {\n      left = mystl::lower_bound(first, last, value, comp);\n      mystl::advance(first, len);\n      right = mystl::upper_bound(++middle, first, value, comp);\n      return mystl::pair<ForwardIter, ForwardIter>(left, right);\n    }\n  }\n  return mystl::pair<ForwardIter, ForwardIter>(last, last);\n}\n\n// erange_dispatch 的 random access iterator 版本\ntemplate <class RandomIter, class T, class Compared>\nmystl::pair<RandomIter, RandomIter>\nerange_dispatch(RandomIter first, RandomIter last,\n                const T& value, random_access_iterator_tag, Compared comp)\n{\n  auto len = last - first;\n  auto half = len;\n  RandomIter middle, left, right;\n  while (len > 0)\n  {\n    half = len >> 1;\n    middle = first + half;\n    if (comp(*middle, value))\n    {\n      first = middle + 1;\n      len = len - half - 1;\n    }\n    else if (comp(value, *middle))\n    {\n      len = half;\n    }\n    else\n    {\n      left = mystl::lower_bound(first, middle, value, comp);\n      right = mystl::upper_bound(++middle, first + len, value, comp);\n      return mystl::pair<RandomIter, RandomIter>(left, right);\n    }\n  }\n  return mystl::pair<RandomIter, RandomIter>(last, last);\n}\n\ntemplate <class ForwardIter, class T, class Compared>\nmystl::pair<ForwardIter, ForwardIter>\nequal_range(ForwardIter first, ForwardIter last, const T& value, Compared comp)\n{\n  return mystl::erange_dispatch(first, last, value, iterator_category(first), comp);\n}\n\n/*****************************************************************************************/\n// generate\n// 将函数对象 gen 的运算结果对[first, last)内的每个元素赋值\n/*****************************************************************************************/\ntemplate <class ForwardIter, class Generator>\nvoid generate(ForwardIter first, ForwardIter last, Generator gen)\n{\n  for (; first != last; ++first)\n  {\n    *first = gen();\n  }\n}\n\n/*****************************************************************************************/\n// generate_n\n// 用函数对象 gen 连续对 n 个元素赋值\n/*****************************************************************************************/\ntemplate <class ForwardIter, class Size, class Generator>\nvoid generate_n(ForwardIter first, Size n, Generator gen)\n{\n  for (; n > 0; --n, ++first)\n  {\n    *first = gen();\n  }\n}\n\n/*****************************************************************************************/\n// includes\n// 判断序列一S1 是否包含序列二S2\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2>\nbool includes(InputIter1 first1, InputIter1 last1,\n              InputIter2 first2, InputIter2 last2)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (*first2 < *first1)\n    {\n      return false;\n    }\n    else if (*first1 < *first2)\n    {\n      ++first1;\n    }\n    else\n    {\n      ++first1, ++first2;\n    }\n  }\n  return first2 == last2;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class Compared>\nbool includes(InputIter1 first1, InputIter1 last1,\n              InputIter2 first2, InputIter2 last2, Compared comp)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (comp(*first2, *first1))\n    {\n      return false;\n    }\n    else if (comp(*first1, *first2))\n    {\n      ++first1;\n    }\n    else\n    {\n      ++first1, ++first2;\n    }\n  }\n  return first2 == last2;\n}\n\n/*****************************************************************************************/\n// is_heap\n// 检查[first, last)内的元素是否为一个堆，如果是，则返回 true\n/*****************************************************************************************/\ntemplate <class RandomIter>\nbool is_heap(RandomIter first, RandomIter last)\n{\n  auto n = mystl::distance(first, last);\n  auto parent = 0;\n  for (auto child = 1; child < n; ++child)\n  {\n    if (first[parent] < first[child])\n      return false;\n    if ((child & 1) == 0)\n      ++parent;\n  }\n  return true;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class RandomIter, class Compared>\nbool is_heap(RandomIter first, RandomIter last, Compared comp)\n{\n  auto n = mystl::distance(first, last);\n  auto parent = 0;\n  for (auto child = 1; child < n; ++child)\n  {\n    if (comp(first[parent], first[child]))\n      return false;\n    if ((child & 1) == 0)\n      ++parent;\n  }\n  return true;\n}\n\n/*****************************************************************************************/\n// is_sorted\n// 检查[first, last)内的元素是否升序，如果是升序，则返回 true\n/*****************************************************************************************/\ntemplate <class ForwardIter>\nbool is_sorted(ForwardIter first, ForwardIter last)\n{\n  if (first == last)\n    return true;\n  auto next = first;\n  ++next;\n  for (; next != last; first = next, ++next)\n  {\n    if (*next < *first)\n      return false;\n  }\n  return true;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter, class Compared>\nbool is_sorted(ForwardIter first, ForwardIter last, Compared comp)\n{\n  if (first == last)\n    return true;\n  auto next = first;\n  ++next;\n  for (; next != last; first = next, ++next)\n  {\n    if (comp(*next, *first))\n      return false;\n  }\n  return true;\n}\n\n/*****************************************************************************************/\n// median\n// 找出三个值的中间值\n/*****************************************************************************************/\ntemplate <class T>\nconst T& median(const T& left, const T& mid, const T& right)\n{\n  if (left < mid)\n    if (mid < right)        // left < mid < right\n      return mid;\n    else if (left < right)  // left < right <= mid\n      return right;\n    else                    // right <= left < mid\n      return left;\n  else if (left < right)      // mid <= left < right\n    return left;\n  else if (mid < right)       // mid < right <= left\n    return right;\n  else                        // right <= mid <= left\n    return mid;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class T, class Compared>\nconst T& median(const T& left, const T& mid, const T& right, Compared comp)\n{\n  if (comp(left, mid))\n    if (comp(mid, right))\n      return mid;\n    else if (comp(left, right))\n      return right;\n    else\n      return left;\n  else if (comp(left, right))\n    return left;\n  else if (comp(mid, right))\n    return right;\n  else\n    return mid;\n}\n\n/*****************************************************************************************/\n// max_element\n// 返回一个迭代器，指向序列中最大的元素\n/*****************************************************************************************/\ntemplate <class ForwardIter>\nForwardIter max_element(ForwardIter first, ForwardIter last)\n{\n  if (first == last)\n    return first;\n  auto result = first;\n  while (++first != last)\n  {\n    if (*result < *first)\n      result = first;\n  }\n  return result;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter, class Compared>\nForwardIter max_element(ForwardIter first, ForwardIter last, Compared comp)\n{\n  if (first == last)\n    return first;\n  auto result = first;\n  while (++first != last)\n  {\n    if (comp(*result, *first))\n      result = first;\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// min_element\n// 返回一个迭代器，指向序列中最小的元素\n/*****************************************************************************************/\ntemplate <class ForwardIter>\nForwardIter min_elememt(ForwardIter first, ForwardIter last)\n{\n  if (first == last)\n    return first;\n  auto result = first;\n  while (++first != last)\n  {\n    if (*first < *result)\n      result = first;\n  }\n  return result;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter, class Compared>\nForwardIter min_elememt(ForwardIter first, ForwardIter last, Compared comp)\n{\n  if (first == last)\n    return first;\n  auto result = first;\n  while (++first != last)\n  {\n    if (comp(*first, *result))\n      result = first;\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// swap_ranges\n// 将[first1, last1)从 first2 开始，交换相同个数元素\n// 交换的区间长度必须相同，两个序列不能互相重叠，返回一个迭代器指向序列二最后一个被交换元素的下一位置\n/*****************************************************************************************/\ntemplate <class ForwardIter1, class ForwardIter2>\nForwardIter2\nswap_ranges(ForwardIter1 first1, ForwardIter1 last1,\n            ForwardIter2 first2)\n{\n  for (; first1 != last1; ++first1, ++first2)\n  {\n    mystl::iter_swap(first1, first2);\n  }\n  return first2;\n}\n\n/*****************************************************************************************/\n// transform\n// 第一个版本以函数对象 unary_op 作用于[first, last)中的每个元素并将结果保存至 result 中\n// 第二个版本以函数对象 binary_op 作用于两个序列[first1, last1)、[first2, last2)的相同位置\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter, class UnaryOperation>\nOutputIter\ntransform(InputIter first, InputIter last,\n          OutputIter result, UnaryOperation unary_op)\n{\n  for (; first != last; ++first, ++result)\n  {\n    *result = unary_op(*first);\n  }\n  return result;\n}\n\ntemplate <class InputIter1, class InputIter2, class OutputIter, class BinaryOperation>\nOutputIter\ntransform(InputIter1 first1, InputIter1 last1,\n          InputIter2 first2, OutputIter result, BinaryOperation binary_op)\n{\n  for (; first1 != last1; ++first1, ++first2, ++result)\n  {\n    *result = binary_op(*first1, *first2);\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// remove_copy\n// 移除区间内与指定 value 相等的元素，并将结果复制到以 result 标示起始位置的容器上\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter, class T>\nOutputIter\nremove_copy(InputIter first, InputIter last, OutputIter result, const T& value)\n{\n  for (; first != last; ++first)\n  {\n    if (*first != value)\n    {\n      *result++ = *first;\n    }\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// remove\n// 移除所有与指定 value 相等的元素\n// 并不从容器中删除这些元素，所以 remove 和 remove_if 不适用于 array\n/*****************************************************************************************/\ntemplate <class ForwardIter, class T>\nForwardIter remove(ForwardIter first, ForwardIter last, const T& value)\n{\n  first = mystl::find(first, last, value);  // 利用 find 找出第一个匹配的地方\n  auto next = first;\n  return first == last ? first : mystl::remove_copy(++next, last, first, value);\n}\n\n/*****************************************************************************************/\n// remove_copy_if\n// 移除区间内所有令一元操作 unary_pred 为 true 的元素，并将结果复制到以 result 为起始位置的容器上\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter, class UnaryPredicate>\nOutputIter\nremove_copy_if(InputIter first, InputIter last,\n               OutputIter result, UnaryPredicate unary_pred)\n{\n  for (; first != last; ++first)\n  {\n    if (!unary_pred(*first))\n    {\n      *result = *first;\n      ++result;\n    }\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// remove_if\n// 移除区间内所有令一元操作 unary_pred 为 true 的元素\n/*****************************************************************************************/\ntemplate <class ForwardIter, class UnaryPredicate>\nForwardIter\nremove_if(ForwardIter first, ForwardIter last, UnaryPredicate unary_pred)\n{\n  first = mystl::find_if(first, last, unary_pred);  // 利用 find_if 找出第一个匹配的地方\n  auto next = first;\n  return first == last ? first : mystl::remove_copy_if(++next, last, first, unary_pred);\n}\n\n/*****************************************************************************************/\n// replace\n// 将区间内所有的 old_value 都以 new_value 替代\n/*****************************************************************************************/\ntemplate <class ForwardIter, class T>\nvoid replace(ForwardIter first, ForwardIter last,\n             const T& old_value, const T& new_value)\n{\n  for (; first != last; ++first)\n  {\n    if (*first == old_value)\n      *first = new_value;\n  }\n}\n\n/*****************************************************************************************/\n// replace_copy\n// 行为与 replace 类似，不同的是将结果复制到 result 所指的容器中，原序列没有改变\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter, class T>\nOutputIter\nreplace_copy(InputIter first, InputIter last,\n             OutputIter result, const T& old_value, const T& new_value)\n{\n  for (; first != last; ++first, ++result)\n  {\n    *result = *first == old_value ? new_value : *first;\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// replace_copy_if\n// 行为与 replace_if 类似，不同的是将结果复制到 result 所指的容器中，原序列没有改变\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter, class UnaryPredicate, class T>\nOutputIter\nreplace_copy_if(InputIter first, InputIter last,\n                OutputIter result, UnaryPredicate unary_pred, const T& new_value)\n{\n  for (; first != last; ++first, ++result)\n  {\n    *result = unary_pred(*first) ? new_value : *first;\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// replace_if\n// 将区间内所有令一元操作 unary_pred 为 true 的元素都用 new_value 替代\n/*****************************************************************************************/\ntemplate <class ForwardIter, class UnaryPredicate, class T>\nvoid replace_if(ForwardIter first, ForwardIter last,\n                UnaryPredicate unary_pred, const T& new_value)\n{\n  for (; first != last; ++first)\n  {\n    if (unary_pred(*first))\n      *first = new_value;\n  }\n}\n\n/*****************************************************************************************/\n// reverse\n// 将[first, last)区间内的元素反转\n/*****************************************************************************************/\n// reverse_dispatch 的 bidirectional_iterator_tag 版本\ntemplate <class BidirectionalIter>\nvoid reverse_dispatch(BidirectionalIter first, BidirectionalIter last,\n                      bidirectional_iterator_tag)\n{\n  while (true)\n  {\n    if (first == last || first == --last)\n      return;\n    mystl::iter_swap(first++, last);\n  }\n}\n\n// reverse_dispatch 的 random_access_iterator_tag 版本\ntemplate <class RandomIter>\nvoid reverse_dispatch(RandomIter first, RandomIter last,\n                      random_access_iterator_tag)\n{\n  while (first < last)\n    mystl::iter_swap(first++, --last);\n}\n\ntemplate <class BidirectionalIter>\nvoid reverse(BidirectionalIter first, BidirectionalIter last)\n{\n  mystl::reverse_dispatch(first, last, iterator_category(first));\n}\n\n/*****************************************************************************************/\n// reverse_copy\n// 行为与 reverse 类似，不同的是将结果复制到 result 所指容器中\n/*****************************************************************************************/\ntemplate <class BidirectionalIter, class OutputIter>\nOutputIter\nreverse_copy(BidirectionalIter first, BidirectionalIter last,\n             OutputIter result)\n{\n  while (first != last)\n  {\n    --last;\n    *result = *last;\n    ++result;\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// random_shuffle\n// 将[first, last)内的元素次序随机重排\n// 重载版本使用一个产生随机数的函数对象 rand\n/*****************************************************************************************/\ntemplate <class RandomIter>\nvoid random_shuffle(RandomIter first, RandomIter last)\n{\n  if (first == last)\n    return;\n  srand((unsigned)time(0));\n  for (auto i = first + 1; i != last; ++i)\n  {\n    mystl::iter_swap(i, first + (rand() % (i - first + 1)));\n  }\n}\n\n// 重载版本使用一个产生随机数的函数对象 rand\ntemplate <class RandomIter, class RandomNumberGenerator>\nvoid random_shuffle(RandomIter first, RandomIter last,\n                    RandomNumberGenerator& rand)\n{\n  if (first == last)\n    return;\n  auto len = mystl::distance(first, last);\n  for (auto i = first + 1; i != last; ++i)\n  {\n    mystl::iter_swap(i, first + (rand(i - first + 1) % len));\n  }\n}\n\n/*****************************************************************************************/\n// rotate\n// 将[first, middle)内的元素和 [middle, last)内的元素互换，可以交换两个长度不同的区间\n// 返回交换后 middle 的位置\n/*****************************************************************************************/\n// rotate_dispatch 的 forward_iterator_tag 版本\ntemplate <class ForwardIter>\nForwardIter\nrotate_dispatch(ForwardIter first, ForwardIter middle,\n                ForwardIter last, forward_iterator_tag)\n{\n  auto first2 = middle;\n  do\n  {\n    mystl::swap(*first++, *first2++);\n    if (first == middle)\n      middle = first2;\n  } while (first2 != last);  // 后半段移到前面\n\n  auto new_middle = first;   // 迭代器返回的位置\n  first2 = middle;\n  while (first2 != last)\n  {   // 调整剩余元素\n    mystl::swap(*first++, *first2++);\n    if (first == middle)\n    {\n      middle = first2;\n    }\n    else if (first2 == last)\n    {\n      first2 = middle;\n    }\n  }\n  return new_middle;\n}\n\n// rotate_dispatch 的 bidirectional_iterator_tag 版本\ntemplate <class BidirectionalIter>\nBidirectionalIter\nrotate_dispatch(BidirectionalIter first, BidirectionalIter middle,\n                BidirectionalIter last, bidirectional_iterator_tag)\n{\n  mystl::reverse_dispatch(first, middle, bidirectional_iterator_tag());\n  mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag());\n  while (first != middle && middle != last)\n    mystl::swap(*first++, *--last);\n  if (first == middle)\n  {\n    mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag());\n    return last;\n  }\n  else\n  {\n    mystl::reverse_dispatch(first, middle, bidirectional_iterator_tag());\n    return first;\n  }\n}\n\n// 求最大公因子\ntemplate <class EuclideanRingElement>\nEuclideanRingElement rgcd(EuclideanRingElement m, EuclideanRingElement n)\n{\n  while (n != 0)\n  {\n    auto t = m % n;\n    m = n;\n    n = t;\n  }\n  return m;\n}\n\n// rotate_dispatch 的 random_access_iterator_tag 版本\ntemplate <class RandomIter>\nRandomIter\nrotate_dispatch(RandomIter first, RandomIter middle,\n                RandomIter last, random_access_iterator_tag)\n{\n  // 因为是 random access iterator，我们可以确定每个元素的位置\n  auto n = last - first;\n  auto l = middle - first;\n  auto r = n - l;\n  auto result = first + (last - middle);\n  if (l == r)\n  {\n    mystl::swap_ranges(first, middle, middle);\n    return result;\n  }\n  auto cycle_times = rgcd(n, l);\n  for (auto i = 0; i < cycle_times; ++i)\n  {\n    auto tmp = *first;\n    auto p = first;\n    if (l < r)\n    {\n      for (auto j = 0; j < r / cycle_times; ++j)\n      {\n        if (p > first + r)\n        {\n          *p = *(p - r);\n          p -= r;\n        }\n        *p = *(p + l);\n        p += l;\n      }\n    }\n    else\n    {\n      for (auto j = 0; j < l / cycle_times - 1; ++j)\n      {\n        if (p < last - l)\n        {\n          *p = *(p + l);\n          p += l;\n        }\n        *p = *(p - r);\n        p -= r;\n      }\n    }\n    *p = tmp;\n    ++first;\n  }\n  return result;\n}\n\ntemplate <class ForwardIter>\nForwardIter\nrotate(ForwardIter first, ForwardIter middle, ForwardIter last)\n{\n  if (first == middle)\n    return last;\n  if (middle == last)\n    return first;\n  return mystl::rotate_dispatch(first, middle, last, iterator_category(first));\n}\n\n/*****************************************************************************************/\n// rotate_copy\n// 行为与 rotate 类似，不同的是将结果复制到 result 所指的容器中\n/*****************************************************************************************/\ntemplate <class ForwardIter, class OutputIter>\nForwardIter\nrotate_copy(ForwardIter first, ForwardIter middle,\n            ForwardIter last, OutputIter result)\n{\n  return mystl::copy(first, middle, mystl::copy(middle, last, result));\n}\n\n/*****************************************************************************************/\n// is_permutation\n// 判断[first1,last1)是否为[first2, last2)的排列组合\n/*****************************************************************************************/\ntemplate <class ForwardIter1, class ForwardIter2, class BinaryPred>\nbool is_permutation_aux(ForwardIter1 first1, ForwardIter1 last1,\n                        ForwardIter2 first2, ForwardIter2 last2,\n                        BinaryPred pred)\n{\n  constexpr bool is_ra_it = mystl::is_random_access_iterator<ForwardIter1>::value\n    && mystl::is_random_access_iterator<ForwardIter2>::value;\n  if (is_ra_it)\n  {\n    auto len1 = last1 - first1;\n    auto len2 = last2 - first2;\n    if (len1 != len2)\n      return false;\n  }\n\n  // 先找出相同的前缀段\n  for (; first1 != last1 && first2 != last2; ++first1, (void) ++first2)\n  {\n    if (!pred(*first1, *first2))\n      break;\n  }\n  if (is_ra_it)\n  {\n    if (first1 == last1)\n      return true;\n  }\n  else\n  {\n    auto len1 = mystl::distance(first1, last1);\n    auto len2 = mystl::distance(first2, last2);\n    if (len1 == 0 && len2 == 0)\n      return true;\n    if (len1 != len2)\n      return false;\n  }\n\n  // 判断剩余部分\n  for (auto i = first1; i != last1; ++i)\n  {\n    bool is_repeated = false;\n    for (auto j = first1; j != i; ++j)\n    {\n      if (pred(*j, *i))\n      {\n        is_repeated = true;\n        break;\n      }\n    }\n\n    if (!is_repeated)\n    {\n      // 计算 *i 在 [first2, last2) 的数目\n      auto c2 = 0;\n      for (auto j = first2; j != last2; ++j)\n      {\n        if (pred(*i, *j))\n          ++c2;\n      }\n      if (c2 == 0)\n        return false;\n\n      // 计算 *i 在 [first1, last1) 的数目\n      auto c1 = 1;\n      auto j = i;\n      for (++j; j != last1; ++j)\n      {\n        if (pred(*i, *j))\n          ++c1;\n      }\n      if (c1 != c2)\n        return false;\n    }\n  }\n  return true;\n}\n\ntemplate <class ForwardIter1, class ForwardIter2, class BinaryPred>\nbool is_permutation(ForwardIter1 first1, ForwardIter1 last1,\n                    ForwardIter2 first2, ForwardIter2 last2,\n                    BinaryPred pred)\n{\n  return is_permutation_aux(first1, last1, first2, last2, pred);\n}\n\ntemplate <class ForwardIter1, class ForwardIter2>\nbool is_permutation(ForwardIter1 first1, ForwardIter1 last1,\n                    ForwardIter2 first2, ForwardIter2 last2)\n{\n  typedef typename iterator_traits<ForwardIter1>::value_type v1;\n  typedef typename iterator_traits<ForwardIter2>::value_type v2;\n  static_assert(std::is_same<v1, v2>::value,\n                \"the type should be same in mystl::is_permutation\");\n  return is_permutation_aux(first1, last1, first2, last2,\n                            mystl::equal_to<v1>());\n}\n\n/*****************************************************************************************/\n// next_permutation\n// 取得[first, last)所标示序列的下一个排列组合，如果没有下一个排序组合，返回 false，否则返回 true\n/*****************************************************************************************/\ntemplate <class BidirectionalIter>\nbool next_permutation(BidirectionalIter first, BidirectionalIter last)\n{\n  auto i = last;\n  if (first == last || first == --i)\n    return false;\n  for (;;)\n  {\n    auto ii = i;\n    if (*--i < *ii)\n    {                 // 找到第一对小于关系的元素\n      auto j = last;\n      while (!(*i < *--j)) {}\n      mystl::iter_swap(i, j);       // 交换 i，j 所指元素\n      mystl::reverse(ii, last);     // 将 ii 之后的所有元素反转\n      return true;\n    }\n    if (i == first)\n    {\n      mystl::reverse(first, last);\n      return false;\n    }\n  }\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class BidirectionalIter, class Compared>\nbool next_permutation(BidirectionalIter first, BidirectionalIter last, Compared comp)\n{\n  auto i = last;\n  if (first == last || first == --i)\n    return false;\n  for (;;)\n  {\n    auto ii = i;\n    if (comp(*--i, *ii))\n    {\n      auto j = last;\n      while (!comp(*i, *--j)) {}\n      mystl::iter_swap(i, j);       // 交换 i，j 所指元素\n      mystl::reverse(ii, last);     // 将 ii 之后的所有元素反转\n      return true;\n    }\n    if (i == first)\n    {\n      mystl::reverse(first, last);\n      return false;\n    }\n  }\n}\n\n/*****************************************************************************************/\n// prev_permutation\n// 取得[first, last)所标示序列的上一个排列组合，如果没有上一个排序组合，返回 false，否则返回 true\n/*****************************************************************************************/\ntemplate <class BidirectionalIter>\nbool prev_permutation(BidirectionalIter first, BidirectionalIter last)\n{\n  auto i = last;\n  if (first == last || first == --i)\n    return false;\n  for (;;)\n  {\n    auto ii = i;\n    if (*ii < *--i)\n    {                 // 找到第一对大于关系的元素\n      auto j = last;\n      while (!(*--j < *i)) {}\n      mystl::iter_swap(i, j);       // 交换i，j\n      mystl::reverse(ii, last);     // 将 ii 之后的所有元素反转\n      return true;\n    }\n    if (i == first)\n    {\n      mystl::reverse(first, last);\n      return false;\n    }\n  }\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class BidirectionalIter, class Compared>\nbool prev_permutation(BidirectionalIter first, BidirectionalIter last, Compared comp)\n{\n  auto i = last;\n  if (first == last || first == --i)\n    return false;\n  for (;;)\n  {\n    auto ii = i;\n    if (comp(*ii, *--i))\n    {\n      auto j = last;\n      while (!comp(*--j, *i)) {}\n      mystl::iter_swap(i, j);       // 交换i，j\n      mystl::reverse(ii, last);     // 将 ii 之后的所有元素反转\n      return true;\n    }\n    if (i == first)\n    {\n      mystl::reverse(first, last);\n      return false;\n    }\n  }\n}\n\n/*****************************************************************************************/\n// merge\n// 将两个经过排序的集合 S1 和 S2 合并起来置于另一段空间，返回一个迭代器指向最后一个元素的下一位置\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2, class OutputIter>\nOutputIter\nmerge(InputIter1 first1, InputIter1 last1,\n      InputIter2 first2, InputIter2 last2,\n      OutputIter result)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (*first2 < *first1)\n    {\n      *result = *first2;\n      ++first2;\n    }\n    else\n    {\n      *result = *first1;\n      ++first1;\n    }\n    ++result;\n  }\n  return mystl::copy(first2, last2, mystl::copy(first1, last1, result));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class OutputIter, class Compared>\nOutputIter\nmerge(InputIter1 first1, InputIter1 last1,\n      InputIter2 first2, InputIter2 last2,\n      OutputIter result, Compared comp)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (comp(*first2, *first1))\n    {\n      *result = *first2;\n      ++first2;\n    }\n    else\n    {\n      *result = *first1;\n      ++first1;\n    }\n    ++result;\n  }\n  return mystl::copy(first2, last2, mystl::copy(first1, last1, result));\n}\n\n/*****************************************************************************************/\n// inplace_merge\n// 把连接在一起的两个有序序列结合成单一序列并保持有序\n/*****************************************************************************************/\n// 没有缓冲区的情况下合并\ntemplate <class BidirectionalIter, class Distance>\nvoid merge_without_buffer(BidirectionalIter first, BidirectionalIter middle,\n                          BidirectionalIter last, Distance len1, Distance len2)\n{\n  if (len1 == 0 || len2 == 0)\n    return;\n  if (len1 + len2 == 2)\n  {\n    if (*middle < *first)\n      mystl::iter_swap(first, middle);\n    return;\n  }\n  auto first_cut = first;\n  auto second_cut = middle;\n  Distance len11 = 0;\n  Distance len22 = 0;\n  if (len1 > len2)\n  {  // 序列一较长，找到序列一的中点\n    len11 = len1 >> 1;\n    mystl::advance(first_cut, len11);\n    second_cut = mystl::lower_bound(middle, last, *first_cut);\n    len22 = mystl::distance(middle, second_cut);\n  }\n  else\n  {              // 序列二较长，找到序列二的中点\n    len22 = len2 >> 1;\n    mystl::advance(second_cut, len22);\n    first_cut = mystl::upper_bound(first, middle, *second_cut);\n    len11 = mystl::distance(first, first_cut);\n  }\n  auto new_middle = mystl::rotate(first_cut, middle, second_cut);\n  mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22);\n  mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, len2 - len22);\n}\n\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter1\nmerge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1,\n               BidirectionalIter2 first2, BidirectionalIter2 last2,\n               BidirectionalIter1 result)\n{\n  if (first1 == last1)\n    return mystl::copy_backward(first2, last2, result);\n  if (first2 == last2)\n    return mystl::copy_backward(first1, last1, result);\n  --last1;\n  --last2;\n  while (true)\n  {\n    if (*last2 < *last1)\n    {\n      *--result = *last1;\n      if (first1 == last1)\n        return mystl::copy_backward(first2, ++last2, result);\n      --last1;\n    }\n    else\n    {\n      *--result = *last2;\n      if (first2 == last2)\n        return mystl::copy_backward(first1, ++last1, result);\n      --last2;\n    }\n  }\n}\n\ntemplate <class BidirectionalIter1, class BidirectionalIter2, class Distance>\nBidirectionalIter1\nrotate_adaptive(BidirectionalIter1 first, BidirectionalIter1 middle,\n                BidirectionalIter1 last, Distance len1, Distance len2,\n                BidirectionalIter2 buffer, Distance buffer_size)\n{\n  BidirectionalIter2 buffer_end;\n  if (len1 > len2 && len2 <= buffer_size)\n  {\n    buffer_end = mystl::copy(middle, last, buffer);\n    mystl::copy_backward(first, middle, last);\n    return mystl::copy(buffer, buffer_end, first);\n  }\n  else if (len1 <= buffer_size)\n  {\n    buffer_end = mystl::copy(first, middle, buffer);\n    mystl::copy(middle, last, first);\n    return mystl::copy_backward(buffer, buffer_end, last);\n  }\n  else\n  {\n    return mystl::rotate(first, middle, last);\n  }\n}\n\n// 有缓冲区的情况下合并\ntemplate <class BidirectionalIter, class Distance, class Pointer>\nvoid merge_adaptive(BidirectionalIter first, BidirectionalIter middle,\n                    BidirectionalIter last, Distance len1, Distance len2,\n                    Pointer buffer, Distance buffer_size)\n{\n  // 区间长度足够放进缓冲区\n  if (len1 <= len2 && len1 <= buffer_size)\n  {\n    Pointer buffer_end = mystl::copy(first, middle, buffer);\n    mystl::merge(buffer, buffer_end, middle, last, first);\n  }\n  else if (len2 <= buffer_size)\n  {\n    Pointer buffer_end = mystl::copy(middle, last, buffer);\n    mystl::merge_backward(first, middle, buffer, buffer_end, last);\n  }\n  else\n  {  // 区间长度太长，分割递归处理\n    auto first_cut = first;\n    auto second_cut = middle;\n    Distance len11 = 0;\n    Distance len22 = 0;\n    if (len1 > len2)\n    {\n      len11 = len1 >> 1;\n      mystl::advance(first_cut, len11);\n      second_cut = mystl::lower_bound(middle, last, *first_cut);\n      len22 = mystl::distance(middle, second_cut);\n    }\n    else\n    {\n      len22 = len2 >> 1;\n      mystl::advance(second_cut, len22);\n      first_cut = mystl::upper_bound(first, middle, *second_cut);\n      len11 = mystl::distance(first, first_cut);\n    }\n    auto new_middle = mystl::rotate_adaptive(first_cut, middle, second_cut,\n                                             len1 - len11, len22, buffer, buffer_size);\n    mystl::merge_adaptive(first, first_cut, new_middle, len11, len22, buffer, buffer_size);\n    mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11,\n                          len2 - len22, buffer, buffer_size);\n  }\n}\n\ntemplate <class BidirectionalIter, class T>\nvoid\ninplace_merge_aux(BidirectionalIter first, BidirectionalIter middle,\n                  BidirectionalIter last, T*)\n{\n  auto len1 = mystl::distance(first, middle);\n  auto len2 = mystl::distance(middle, last);\n  temporary_buffer<BidirectionalIter, T> buf(first, last);\n  if (!buf.begin())\n  {\n    mystl::merge_without_buffer(first, middle, last, len1, len2);\n  }\n  else\n  {\n    mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), buf.size());\n  }\n}\n\ntemplate <class BidirectionalIter>\nvoid\ninplace_merge(BidirectionalIter first, BidirectionalIter middle,\n              BidirectionalIter last)\n{\n  if (first == middle || middle == last)\n    return;\n  mystl::inplace_merge_aux(first, middle, last, value_type(first));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\n// 没有缓冲区的情况下合并\ntemplate <class BidirectionalIter, class Distance, class Compared>\nvoid merge_without_buffer(BidirectionalIter first, BidirectionalIter middle,\n                          BidirectionalIter last, Distance len1, Distance len2,\n                          Compared comp)\n{\n  if (len1 == 0 || len2 == 0)\n    return;\n  if (len1 + len2 == 2)\n  {\n    if (comp(*middle, *first))\n      mystl::iter_swap(first, middle);\n    return;\n  }\n  auto first_cut = first;\n  auto second_cut = middle;\n  Distance len11 = 0;\n  Distance len22 = 0;\n  if (len1 > len2)\n  {\n    len11 = len1 >> 1;\n    mystl::advance(first_cut, len11);\n    second_cut = mystl::lower_bound(middle, last, *first_cut, comp);\n    len22 = mystl::distance(middle, second_cut);\n  }\n  else\n  {\n    len22 = len2 >> 1;\n    mystl::advance(second_cut, len22);\n    first_cut = mystl::upper_bound(first, middle, *second_cut, comp);\n    len11 = mystl::distance(first, first_cut);\n  }\n  auto new_middle = mystl::rotate(first_cut, middle, second_cut);\n  mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22, comp);\n  mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);\n}\n\ntemplate <class BidirectionalIter1, class BidirectionalIter2, class Compared>\nBidirectionalIter1\nmerge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1,\n               BidirectionalIter2 first2, BidirectionalIter2 last2,\n               BidirectionalIter1 result, Compared comp)\n{\n  if (first1 == last1)\n    return mystl::copy_backward(first2, last2, result);\n  if (first2 == last2)\n    return mystl::copy_backward(first1, last1, result);\n  --last1;\n  --last2;\n  while (true)\n  {\n    if (comp(*last2, *last1))\n    {\n      *--result = *last1;\n      if (first1 == last1)\n        return mystl::copy_backward(first2, ++last2, result);\n      --last1;\n    }\n    else\n    {\n      *--result = *last2;\n      if (first2 == last2)\n        return mystl::copy_backward(first1, ++last1, result);\n      --last2;\n    }\n  }\n}\n\n// 有缓冲区的情况下合并\ntemplate <class BidirectionalIter, class Distance, class Pointer, class Compared>\nvoid merge_adaptive(BidirectionalIter first, BidirectionalIter middle,\n                    BidirectionalIter last, Distance len1, Distance len2,\n                    Pointer buffer, Distance buffer_size, Compared comp)\n{\n  // 区间长度足够放进缓冲区\n  if (len1 <= len2 && len1 <= buffer_size)\n  {\n    Pointer buffer_end = mystl::copy(first, middle, buffer);\n    mystl::merge(buffer, buffer_end, middle, last, first, comp);\n  }\n  else if (len2 <= buffer_size)\n  {\n    Pointer buffer_end = mystl::copy(middle, last, buffer);\n    mystl::merge_backward(first, middle, buffer, buffer_end, last, comp);\n  }\n  else\n  {  // 区间长度太长，分割递归处理\n    auto first_cut = first;\n    auto second_cut = middle;\n    Distance len11 = 0;\n    Distance len22 = 0;\n    if (len1 > len2)\n    {\n      len11 = len1 >> 1;\n      mystl::advance(first_cut, len11);\n      second_cut = mystl::lower_bound(middle, last, *first_cut, comp);\n      len22 = mystl::distance(middle, second_cut);\n    }\n    else\n    {\n      len22 = len2 >> 1;\n      mystl::advance(second_cut, len22);\n      first_cut = mystl::upper_bound(first, middle, *second_cut, comp);\n      len11 = mystl::distance(first, first_cut);\n    }\n    auto new_middle = mystl::rotate_adaptive(first_cut, middle, second_cut, len1 - len11,\n                                             len22, buffer, buffer_size);\n    mystl::merge_adaptive(first, first_cut, new_middle, len11,\n                          len22, buffer, buffer_size, comp);\n    mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11,\n                          len2 - len22, buffer, buffer_size, comp);\n  }\n}\n\ntemplate <class BidirectionalIter, class T, class Compared>\nvoid\ninplace_merge_aux(BidirectionalIter first, BidirectionalIter middle,\n                  BidirectionalIter last, T*, Compared comp)\n{\n  auto len1 = mystl::distance(first, middle);\n  auto len2 = mystl::distance(middle, last);\n  temporary_buffer<BidirectionalIter, T> buf(first, last);\n  if (!buf.begin())\n  {\n    mystl::merge_without_buffer(first, middle, last, len1, len2, comp);\n  }\n  else\n  {\n    mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), buf.size(), comp);\n  }\n}\n\ntemplate <class BidirectionalIter, class Compared>\nvoid\ninplace_merge(BidirectionalIter first, BidirectionalIter middle,\n              BidirectionalIter last, Compared comp)\n{\n  if (first == middle || middle == last)\n    return;\n  mystl::inplace_merge_aux(first, middle, last, value_type(first), comp);\n}\n\n/*****************************************************************************************/\n// partial_sort\n// 对整个序列做部分排序，保证较小的 N 个元素以递增顺序置于[first, first + N)中\n/*****************************************************************************************/\ntemplate <class RandomIter>\nvoid partial_sort(RandomIter first, RandomIter middle,\n                  RandomIter last)\n{\n  mystl::make_heap(first, middle);\n  for (auto i = middle; i < last; ++i)\n  {\n    if (*i < *first)\n    {\n      mystl::pop_heap_aux(first, middle, i, *i, distance_type(first));\n    }\n  }\n  mystl::sort_heap(first, middle);\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class RandomIter, class Compared>\nvoid partial_sort(RandomIter first, RandomIter middle,\n                  RandomIter last, Compared comp)\n{\n  mystl::make_heap(first, middle, comp);\n  for (auto i = middle; i < last; ++i)\n  {\n    if (comp(*i, *first))\n    {\n      mystl::pop_heap_aux(first, middle, i, *i, distance_type(first), comp);\n    }\n  }\n  mystl::sort_heap(first, middle, comp);\n}\n\n/*****************************************************************************************/\n// partial_sort_copy\n// 行为与 partial_sort 类似，不同的是把排序结果复制到 result 容器中\n/*****************************************************************************************/\ntemplate <class InputIter, class RandomIter, class Distance>\nRandomIter\npsort_copy_aux(InputIter first, InputIter last,\n               RandomIter result_first, RandomIter result_last,\n               Distance*)\n{\n  if (result_first == result_last)\n    return result_last;\n  auto result_iter = result_first;\n  while (first != last && result_iter != result_last)\n  {\n    *result_iter = *first;\n    ++result_iter;\n    ++first;\n  }\n  mystl::make_heap(result_first, result_iter);\n  while (first != last)\n  {\n    if (*first < *result_first)\n    {\n      mystl::adjust_heap(result_first, static_cast<Distance>(0),\n                           result_iter - result_first, *first);\n    }\n    ++first;\n  }\n  mystl::sort_heap(result_first, result_iter);\n  return result_iter;\n}\n\ntemplate <class InputIter, class RandomIter>\nRandomIter\npartial_sort_copy(InputIter first, InputIter last,\n                  RandomIter result_first, RandomIter result_last)\n{\n  return mystl::psort_copy_aux(first, last, result_first, result_last,\n                               distance_type(result_first));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter, class RandomIter, class Distance, class Compared>\nRandomIter\npsort_copy_aux(InputIter first, InputIter last,\n               RandomIter result_first, RandomIter result_last,\n               Distance*, Compared comp)\n{\n  if (result_first == result_last)\n    return result_last;\n  auto result_iter = result_first;\n  while (first != last && result_iter != result_last)\n  {\n    *result_iter = *first;\n    ++result_iter;\n    ++first;\n  }\n  mystl::make_heap(result_first, result_iter, comp);\n  while (first != last)\n  {\n    if (comp(*first, *result_first))\n    {\n      mystl::adjust_heap(result_first, static_cast<Distance>(0),\n                           result_iter - result_first, *first, comp);\n    }\n    ++first;\n  }\n  mystl::sort_heap(result_first, result_iter, comp);\n  return result_iter;\n}\n\ntemplate <class InputIter, class RandomIter, class Compared>\nRandomIter\npartial_sort_copy(InputIter first, InputIter last,\n                  RandomIter result_first, RandomIter result_last,\n                  Compared comp)\n{\n  return mystl::psort_copy_aux(first, last, result_first, result_last,\n                               distance_type(result_first), comp);\n}\n/*****************************************************************************************/\n// partition\n// 对区间内的元素重排，被一元条件运算判定为 true 的元素会放到区间的前段\n// 该函数不保证元素的原始相对位置\n/*****************************************************************************************/\ntemplate <class BidirectionalIter, class UnaryPredicate>\nBidirectionalIter\npartition(BidirectionalIter first, BidirectionalIter last,\n          UnaryPredicate unary_pred)\n{\n  while (true)\n  {\n    while (first != last && unary_pred(*first))\n    {\n      ++first;\n    }\n    if (first == last)\n      break;\n    --last;\n    while (first != last && !unary_pred(*last))\n    {\n      --last;\n    }\n    if (first == last)\n      break;\n    mystl::iter_swap(first, last);\n    ++first;\n  }\n  return first;\n}\n\n/*****************************************************************************************/\n// partition_copy\n// 行为与 partition 类似，不同的是，将被一元操作符判定为 true 的放到 result_true 的输出区间\n// 其余放到 result_false 的输出区间，并返回一个 mystl::pair 指向这两个区间的尾部\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter1, class OutputIter2, class UnaryPredicate>\nmystl::pair<OutputIter1, OutputIter2>\npartition_copy(InputIter first, InputIter last,\n               OutputIter1 result_true, OutputIter2 result_false,\n               UnaryPredicate unary_pred)\n{\n  for (; first != last; ++first)\n  {\n    if (unary_pred(*first))\n    {\n      *result_true++ = *first;\n    }\n    else\n    {\n      *result_false++ = *first;\n    }\n  }\n  return mystl::pair<OutputIter1, OutputIter2>(result_true, result_false);\n}\n\n/*****************************************************************************************/\n// sort\n// 将[first, last)内的元素以递增的方式排序\n/*****************************************************************************************/\nconstexpr static size_t kSmallSectionSize = 128;  // 小型区间的大小，在这个大小内采用插入排序\n\n                                                  // 用于控制分割恶化的情况\ntemplate <class Size>\nSize slg2(Size n)\n{ // 找出 lgk <= n 的 k 的最大值\n  Size k = 0;\n  for (; n > 1; n >>= 1)\n    ++k;\n  return k;\n}\n\n// 分割函数 unchecked_partition\ntemplate <class RandomIter, class T>\nRandomIter\nunchecked_partition(RandomIter first, RandomIter last, const T& pivot)\n{\n  while (true)\n  {\n    while (*first < pivot)\n      ++first;\n    --last;\n    while (pivot < *last)\n      --last;\n    if (!(first < last))\n      return first;\n    mystl::iter_swap(first, last);\n    ++first;\n  }\n}\n\n// 内省式排序，先进行 quick sort，当分割行为有恶化倾向时，改用 heap sort\ntemplate <class RandomIter, class Size>\nvoid intro_sort(RandomIter first, RandomIter last, Size depth_limit)\n{\n  while (static_cast<size_t>(last - first) > kSmallSectionSize)\n  {\n    if (depth_limit == 0)\n    {                      // 到达最大分割深度限制\n      mystl::partial_sort(first, last, last);  // 改用 heap_sort\n      return;\n    }\n    --depth_limit;\n    auto mid = mystl::median(*(first), *(first + (last - first) / 2), *(last - 1));\n    auto cut = mystl::unchecked_partition(first, last, mid);\n    mystl::intro_sort(cut, last, depth_limit);\n    last = cut;\n  }\n}\n\n// 插入排序辅助函数 unchecked_linear_insert\ntemplate <class RandomIter, class T>\nvoid unchecked_linear_insert(RandomIter last, const T& value)\n{\n  auto next = last;\n  --next;\n  while (value < *next)\n  {\n    *last = *next;\n    last = next;\n    --next;\n  }\n  *last = value;\n}\n\n// 插入排序函数 unchecked_insertion_sort\ntemplate <class RandomIter>\nvoid unchecked_insertion_sort(RandomIter first, RandomIter last)\n{\n  for (auto i = first; i != last; ++i)\n  {\n    mystl::unchecked_linear_insert(i, *i);\n  }\n}\n\n// 插入排序函数 insertion_sort\ntemplate <class RandomIter>\nvoid insertion_sort(RandomIter first, RandomIter last)\n{\n  if (first == last)\n    return;\n  for (auto i = first + 1; i != last; ++i)\n  {\n    auto value = *i;\n    if (value < *first)\n    {\n      mystl::copy_backward(first, i, i + 1);\n      *first = value;\n    }\n    else\n    {\n      mystl::unchecked_linear_insert(i, value);\n    }\n  }\n}\n\n// 最终插入排序函数 final_insertion_sort\ntemplate <class RandomIter>\nvoid final_insertion_sort(RandomIter first, RandomIter last)\n{\n  if (static_cast<size_t>(last - first) > kSmallSectionSize)\n  {\n    mystl::insertion_sort(first, first + kSmallSectionSize);\n    mystl::unchecked_insertion_sort(first + kSmallSectionSize, last);\n  }\n  else\n  {\n    mystl::insertion_sort(first, last);\n  }\n}\n\ntemplate <class RandomIter>\nvoid sort(RandomIter first, RandomIter last)\n{\n  if (first != last)\n  {\n    // 内省式排序，将区间分为一个个小区间，然后对整体进行插入排序\n    mystl::intro_sort(first, last, slg2(last - first) * 2);\n    mystl::final_insertion_sort(first, last);\n  }\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\n// 分割函数 unchecked_partition\ntemplate <class RandomIter, class T, class Compared>\nRandomIter\nunchecked_partition(RandomIter first, RandomIter last,\n                    const T& pivot, Compared comp)\n{\n  while (true)\n  {\n    while (comp(*first, pivot))\n      ++first;\n    --last;\n    while (comp(pivot, *last))\n      --last;\n    if (!(first < last))\n      return first;\n    mystl::iter_swap(first, last);\n    ++first;\n  }\n}\n\n// 内省式排序，先进行 quick sort，当分割行为有恶化倾向时，改用 heap sort\ntemplate <class RandomIter, class Size, class Compared>\nvoid intro_sort(RandomIter first, RandomIter last,\n                Size depth_limit, Compared comp)\n{\n  while (static_cast<size_t>(last - first) > kSmallSectionSize)\n  {\n    if (depth_limit == 0)\n    {                            // 到达最大分割深度限制\n      mystl::partial_sort(first, last, last, comp);  // 改用 heap_sort\n      return;\n    }\n    --depth_limit;\n    auto mid = mystl::median(*(first), *(first + (last - first) / 2), *(last - 1));\n    auto cut = mystl::unchecked_partition(first, last, mid, comp);\n    mystl::intro_sort(cut, last, depth_limit, comp);\n    last = cut;\n  }\n}\n\n// 插入排序辅助函数 unchecked_linear_insert\ntemplate <class RandomIter, class T, class Compared>\nvoid unchecked_linear_insert(RandomIter last, const T& value, Compared comp)\n{\n  auto next = last;\n  --next;\n  while (comp(value, *next))\n  {  // 从尾部开始寻找第一个可插入位置\n    *last = *next;\n    last = next;\n    --next;\n  }\n  *last = value;\n}\n\n// 插入排序函数 unchecked_insertion_sort\ntemplate <class RandomIter, class Compared>\nvoid unchecked_insertion_sort(RandomIter first, RandomIter last,\n                              Compared comp)\n{\n  for (auto i = first; i != last; ++i)\n  {\n    mystl::unchecked_linear_insert(i, *i, comp);\n  }\n}\n\n// 插入排序函数 insertion_sort\ntemplate <class RandomIter, class Compared>\nvoid insertion_sort(RandomIter first, RandomIter last, Compared comp)\n{\n  if (first == last)\n    return;\n  for (auto i = first + 1; i != last; ++i)\n  {\n    auto value = *i;\n    if (comp(value, *first))\n    {\n      mystl::copy_backward(first, i, i + 1);\n      *first = value;\n    }\n    else\n    {\n      mystl::unchecked_linear_insert(i, value, comp);\n    }\n  }\n}\n\n// 最终插入排序函数 final_insertion_sort\ntemplate <class RandomIter, class Compared>\nvoid final_insertion_sort(RandomIter first, RandomIter last, Compared comp)\n{\n  if (static_cast<size_t>(last - first) > kSmallSectionSize)\n  {\n    mystl::insertion_sort(first, first + kSmallSectionSize, comp);\n    mystl::unchecked_insertion_sort(first + kSmallSectionSize, last, comp);\n  }\n  else\n  {\n    mystl::insertion_sort(first, last, comp);\n  }\n}\n\ntemplate <class RandomIter, class Compared>\nvoid sort(RandomIter first, RandomIter last, Compared comp)\n{\n  if (first != last)\n  {\n    // 内省式排序，将区间分为一个个小区间，然后对整体进行插入排序\n    mystl::intro_sort(first, last, slg2(last - first) * 2, comp);\n    mystl::final_insertion_sort(first, last, comp);\n  }\n}\n\n/*****************************************************************************************/\n// nth_element\n// 对序列重排，使得所有小于第 n 个元素的元素出现在它的前面，大于它的出现在它的后面\n/*****************************************************************************************/\ntemplate <class RandomIter>\nvoid nth_element(RandomIter first, RandomIter nth,\n                 RandomIter last)\n{\n  if (nth == last)\n    return;\n  while (last - first > 3)\n  {\n    auto cut = mystl::unchecked_partition(first, last, mystl::median(*first,\n\t\t\t\t\t\t\t\t\t\t  *(first + (last - first) / 2),\n\t\t\t\t\t\t\t\t\t\t  *(last - 1)));\n    if (cut <= nth)  // 如果 nth 位于右段\n      first = cut;   // 对右段进行分割\n    else\n      last = cut;    // 对左段进行分割\n  }\n  mystl::insertion_sort(first, last);\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class RandomIter, class Compared>\nvoid nth_element(RandomIter first, RandomIter nth,\n                 RandomIter last, Compared comp)\n{\n  if (nth == last)\n    return;\n  while (last - first > 3)\n  {\n    auto cut = mystl::unchecked_partition(first, last, mystl::median(*first, \n\t\t\t\t\t\t\t\t\t\t  *(first + (last - first) / 2),\n\t\t\t\t\t\t\t\t\t\t  *(last - 1)), comp);\n    if (cut <= nth)  // 如果 nth 位于右段\n      first = cut;   // 对右段进行分割\n    else\n      last = cut;    // 对左段进行分割\n  }\n  mystl::insertion_sort(first, last, comp);\n}\n\n/*****************************************************************************************/\n// unique_copy\n// 从[first, last)中将元素复制到 result 上，序列必须有序，如果有重复的元素，只会复制一次\n/*****************************************************************************************/\n// unique_copy_dispatch 的 forward_iterator_tag 版本\ntemplate <class InputIter, class ForwardIter>\nForwardIter\nunique_copy_dispatch(InputIter first, InputIter last,\n                     ForwardIter result, forward_iterator_tag)\n{\n  *result = *first;\n  while (++first != last)\n  {\n    if (*result != *first)\n      *++result = *first;\n  }\n  return ++result;\n}\n\n// unique_copy_dispatch 的 output_iterator_tag 版本\n// 由于 output iterator 只能进行只读操作，所以不能有 *result != *first 这样的判断\ntemplate <class InputIter, class OutputIter>\nOutputIter\nunique_copy_dispatch(InputIter first, InputIter last,\n                     OutputIter result, output_iterator_tag)\n{\n  auto value = *first;\n  *result = value;\n  while (++first != last)\n  {\n    if (value != *first)\n    {\n      value = *first;\n      *++result = value;\n    }\n  }\n  return ++result;\n}\n\ntemplate <class InputIter, class OutputIter>\nOutputIter\nunique_copy(InputIter first, InputIter last, OutputIter result)\n{\n  if (first == last)\n    return result;\n  return mystl::unique_copy_dispatch(first, last, result, iterator_category(result));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\n// unique_copy_dispatch 的 forward_iterator_tag 版本\ntemplate <class InputIter, class ForwardIter, class Compared>\nForwardIter\nunique_copy_dispatch(InputIter first, InputIter last,\n                     ForwardIter result, forward_iterator_tag, Compared comp)\n{\n  *result = *first;\n  while (++first != last)\n  {\n    if (!comp(*result, *first))\n      *++result = *first;\n  }\n  return ++result;\n}\n\n// unique_copy_dispatch 的 output_iterator_tag 版本\n// 由于 output iterator 只能进行只读操作，所以不能有 *result != *first 这样的判断\ntemplate <class InputIter, class OutputIter, class Compared>\nOutputIter\nunique_copy_dispatch(InputIter first, InputIter last,\n                     OutputIter result, output_iterator_tag, Compared comp)\n{\n  auto value = *first;\n  *result = value;\n  while (++first != last)\n  {\n    if (!comp(value, *first))\n    {\n      value = *first;\n      *++result = value;\n    }\n  }\n  return ++result;\n}\n\ntemplate <class InputIter, class OutputIter, class Compared>\nOutputIter\nunique_copy(InputIter first, InputIter last, OutputIter result, Compared comp)\n{\n  if (first == last)\n    return result;\n  return mystl::unique_copy_dispatch(first, last, result, iterator_category(result), comp);\n}\n\n/*****************************************************************************************/\n// unique\n// 移除[first, last)内重复的元素，序列必须有序，和 remove 类似，它也不能真正的删除重复元素\n/*****************************************************************************************/\ntemplate <class ForwardIter>\nForwardIter unique(ForwardIter first, ForwardIter last)\n{\n  first = mystl::adjacent_find(first, last);\n  return mystl::unique_copy(first, last, first);\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class ForwardIter, class Compared>\nForwardIter unique(ForwardIter first, ForwardIter last, Compared comp)\n{\n  first = mystl::adjacent_find(first, last, comp);\n  return mystl::unique_copy(first, last, first, comp);\n}\n\n} // namespace mystl\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n#endif // !MYTINYSTL_ALGO_H_\n\n"
  },
  {
    "path": "MyTinySTL/algobase.h",
    "content": "﻿#ifndef MYTINYSTL_ALGOBASE_H_\n#define MYTINYSTL_ALGOBASE_H_\n\n// 这个头文件包含了 mystl 的基本算法\n\n#include <cstring>\n\n#include \"iterator.h\"\n#include \"util.h\"\n\nnamespace mystl\n{\n\n#ifdef max\n#pragma message(\"#undefing marco max\")\n#undef max\n#endif // max\n\n#ifdef min\n#pragma message(\"#undefing marco min\")\n#undef min\n#endif // min\n\n/*****************************************************************************************/\n// max\n// 取二者中的较大值，语义相等时保证返回第一个参数\n/*****************************************************************************************/\ntemplate <class T>\nconst T& max(const T& lhs, const T& rhs)\n{\n  return lhs < rhs ? rhs : lhs;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class T, class Compare>\nconst T& max(const T& lhs, const T& rhs, Compare comp)\n{\n  return comp(lhs, rhs) ? rhs : lhs;\n}\n\n/*****************************************************************************************/\n// min \n// 取二者中的较小值，语义相等时保证返回第一个参数\n/*****************************************************************************************/\ntemplate <class T>\nconst T& min(const T& lhs, const T& rhs)\n{\n  return rhs < lhs ? rhs : lhs;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class T, class Compare>\nconst T& min(const T& lhs, const T& rhs, Compare comp)\n{\n  return comp(rhs, lhs) ? rhs : lhs;\n}\n\n/*****************************************************************************************/\n// iter_swap\n// 将两个迭代器所指对象对调\n/*****************************************************************************************/\ntemplate <class FIter1, class FIter2>\nvoid iter_swap(FIter1 lhs, FIter2 rhs)\n{\n  mystl::swap(*lhs, *rhs);\n}\n\n/*****************************************************************************************/\n// copy\n// 把 [first, last)区间内的元素拷贝到 [result, result + (last - first))内\n/*****************************************************************************************/\n// input_iterator_tag 版本\ntemplate <class InputIter, class OutputIter>\nOutputIter \nunchecked_copy_cat(InputIter first, InputIter last, OutputIter result, \n                   mystl::input_iterator_tag)\n{\n  for (; first != last; ++first, ++result)\n  {\n    *result = *first;\n  }\n  return result;\n}\n\n// ramdom_access_iterator_tag 版本\ntemplate <class RandomIter, class OutputIter>\nOutputIter \nunchecked_copy_cat(RandomIter first, RandomIter last, OutputIter result,\n                   mystl::random_access_iterator_tag)\n{\n  for (auto n = last - first; n > 0; --n, ++first, ++result)\n  {\n    *result = *first;\n  }\n  return result;\n}\n\ntemplate <class InputIter, class OutputIter>\nOutputIter \nunchecked_copy(InputIter first, InputIter last, OutputIter result)\n{\n  return unchecked_copy_cat(first, last, result, iterator_category(first));\n}\n\n// 为 trivially_copy_assignable 类型提供特化版本\ntemplate <class Tp, class Up>\ntypename std::enable_if<\n  std::is_same<typename std::remove_const<Tp>::type, Up>::value &&\n  std::is_trivially_copy_assignable<Up>::value,\n  Up*>::type\nunchecked_copy(Tp* first, Tp* last, Up* result)\n{\n  const auto n = static_cast<size_t>(last - first);\n  if (n != 0)\n    std::memmove(result, first, n * sizeof(Up));\n  return result + n;\n}\n\ntemplate <class InputIter, class OutputIter>\nOutputIter copy(InputIter first, InputIter last, OutputIter result)\n{\n  return unchecked_copy(first, last, result);\n}\n\n/*****************************************************************************************/\n// copy_backward\n// 将 [first, last)区间内的元素拷贝到 [result - (last - first), result)内\n/*****************************************************************************************/\n// unchecked_copy_backward_cat 的 bidirectional_iterator_tag 版本\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter2 \nunchecked_copy_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last,\n                            BidirectionalIter2 result, mystl::bidirectional_iterator_tag)\n{\n  while (first != last)\n    *--result = *--last;\n  return result;\n}\n\n// unchecked_copy_backward_cat 的 random_access_iterator_tag 版本\ntemplate <class RandomIter1, class BidirectionalIter2>\nBidirectionalIter2 \nunchecked_copy_backward_cat(RandomIter1 first, RandomIter1 last,\n                            BidirectionalIter2 result, mystl::random_access_iterator_tag)\n{\n  for (auto n = last - first; n > 0; --n)\n    *--result = *--last;\n  return result;\n}\n\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter2 \nunchecked_copy_backward(BidirectionalIter1 first, BidirectionalIter1 last,\n                        BidirectionalIter2 result)\n{\n  return unchecked_copy_backward_cat(first, last, result,\n                                     iterator_category(first));\n}\n\n// 为 trivially_copy_assignable 类型提供特化版本\ntemplate <class Tp, class Up>\ntypename std::enable_if<\n  std::is_same<typename std::remove_const<Tp>::type, Up>::value &&\n  std::is_trivially_copy_assignable<Up>::value,\n  Up*>::type\nunchecked_copy_backward(Tp* first, Tp* last, Up* result)\n{\n  const auto n = static_cast<size_t>(last - first);\n  if (n != 0)\n  {\n    result -= n;\n    std::memmove(result, first, n * sizeof(Up));\n  }\n  return result;\n}\n\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter2 \ncopy_backward(BidirectionalIter1 first, BidirectionalIter1 last, BidirectionalIter2 result)\n{\n  return unchecked_copy_backward(first, last, result);\n}\n\n/*****************************************************************************************/\n// copy_if\n// 把[first, last)内满足一元操作 unary_pred 的元素拷贝到以 result 为起始的位置上\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter, class UnaryPredicate>\nOutputIter \ncopy_if(InputIter first, InputIter last, OutputIter result, UnaryPredicate unary_pred)\n{\n  for (; first != last; ++first)\n  {\n    if (unary_pred(*first))\n      *result++ = *first;\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// copy_n\n// 把 [first, first + n)区间上的元素拷贝到 [result, result + n)上\n// 返回一个 pair 分别指向拷贝结束的尾部\n/*****************************************************************************************/\ntemplate <class InputIter, class Size, class OutputIter>\nmystl::pair<InputIter, OutputIter>\nunchecked_copy_n(InputIter first, Size n, OutputIter result, mystl::input_iterator_tag)\n{\n  for (; n > 0; --n, ++first, ++result)\n  {\n    *result = *first;\n  }\n  return mystl::pair<InputIter, OutputIter>(first, result);\n}\n\ntemplate <class RandomIter, class Size, class OutputIter>\nmystl::pair<RandomIter, OutputIter>\nunchecked_copy_n(RandomIter first, Size n, OutputIter result, \n                 mystl::random_access_iterator_tag)\n{\n  auto last = first + n;\n  return mystl::pair<RandomIter, OutputIter>(last, mystl::copy(first, last, result));\n}\n\ntemplate <class InputIter, class Size, class OutputIter>\nmystl::pair<InputIter, OutputIter> \ncopy_n(InputIter first, Size n, OutputIter result)\n{\n  return unchecked_copy_n(first, n, result, iterator_category(first));\n}\n\n/*****************************************************************************************/\n// move\n// 把 [first, last)区间内的元素移动到 [result, result + (last - first))内\n/*****************************************************************************************/\n// input_iterator_tag 版本\ntemplate <class InputIter, class OutputIter>\nOutputIter \nunchecked_move_cat(InputIter first, InputIter last, OutputIter result,\n                   mystl::input_iterator_tag)\n{\n  for (; first != last; ++first, ++result)\n  {\n    *result = mystl::move(*first);\n  }\n  return result;\n}\n\n// ramdom_access_iterator_tag 版本\ntemplate <class RandomIter, class OutputIter>\nOutputIter \nunchecked_move_cat(RandomIter first, RandomIter last, OutputIter result,\n                   mystl::random_access_iterator_tag)\n{\n  for (auto n = last - first; n > 0; --n, ++first, ++result)\n  {\n    *result = mystl::move(*first);\n  }\n  return result;\n}\n\ntemplate <class InputIter, class OutputIter>\nOutputIter \nunchecked_move(InputIter first, InputIter last, OutputIter result)\n{\n  return unchecked_move_cat(first, last, result, iterator_category(first));\n}\n\n// 为 trivially_copy_assignable 类型提供特化版本\ntemplate <class Tp, class Up>\ntypename std::enable_if<\n  std::is_same<typename std::remove_const<Tp>::type, Up>::value &&\n  std::is_trivially_move_assignable<Up>::value,\n  Up*>::type\nunchecked_move(Tp* first, Tp* last, Up* result)\n{\n  const size_t n = static_cast<size_t>(last - first);\n  if (n != 0)\n    std::memmove(result, first, n * sizeof(Up));\n  return result + n;\n}\n\ntemplate <class InputIter, class OutputIter>\nOutputIter move(InputIter first, InputIter last, OutputIter result)\n{\n  return unchecked_move(first, last, result);\n}\n\n/*****************************************************************************************/\n// move_backward\n// 将 [first, last)区间内的元素移动到 [result - (last - first), result)内\n/*****************************************************************************************/\n// bidirectional_iterator_tag 版本\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter2\nunchecked_move_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last,\n                            BidirectionalIter2 result, mystl::bidirectional_iterator_tag)\n{\n  while (first != last)\n    *--result = mystl::move(*--last);\n  return result;\n}\n\n// random_access_iterator_tag 版本\ntemplate <class RandomIter1, class RandomIter2>\nRandomIter2\nunchecked_move_backward_cat(RandomIter1 first, RandomIter1 last,\n                            RandomIter2 result, mystl::random_access_iterator_tag)\n{\n  for (auto n = last - first; n > 0; --n)\n    *--result = mystl::move(*--last);\n  return result;\n}\n\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter2\nunchecked_move_backward(BidirectionalIter1 first, BidirectionalIter1 last, \n                        BidirectionalIter2 result)\n{\n  return unchecked_move_backward_cat(first, last, result,\n                                     iterator_category(first));\n}\n\n// 为 trivially_copy_assignable 类型提供特化版本\ntemplate <class Tp, class Up>\ntypename std::enable_if<\n  std::is_same<typename std::remove_const<Tp>::type, Up>::value &&\n  std::is_trivially_move_assignable<Up>::value,\n  Up*>::type\nunchecked_move_backward(Tp* first, Tp* last, Up* result)\n{\n  const size_t n = static_cast<size_t>(last - first);\n  if (n != 0)\n  {\n    result -= n;\n    std::memmove(result, first, n * sizeof(Up));\n  }\n  return result;\n}\n\ntemplate <class BidirectionalIter1, class BidirectionalIter2>\nBidirectionalIter2\nmove_backward(BidirectionalIter1 first, BidirectionalIter1 last, BidirectionalIter2 result)\n{\n  return unchecked_move_backward(first, last, result);\n}\n\n/*****************************************************************************************/\n// equal\n// 比较第一序列在 [first, last)区间上的元素值是否和第二序列相等\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2>\nbool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2)\n{\n  for (; first1 != last1; ++first1, ++first2)\n  {\n    if (*first1 != *first2)  \n      return false;\n  }\n  return true;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class Compared>\nbool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, Compared comp)\n{\n  for (; first1 != last1; ++first1, ++first2)\n  {\n    if (!comp(*first1, *first2))  \n      return false;\n  }\n  return true;\n}\n\n/*****************************************************************************************/\n// fill_n\n// 从 first 位置开始填充 n 个值\n/*****************************************************************************************/\ntemplate <class OutputIter, class Size, class T>\nOutputIter unchecked_fill_n(OutputIter first, Size n, const T& value)\n{\n  for (; n > 0; --n, ++first)\n  {\n    *first = value;\n  }\n  return first;\n}\n\n// 为 one-byte 类型提供特化版本\ntemplate <class Tp, class Size, class Up>\ntypename std::enable_if<\n  std::is_integral<Tp>::value && sizeof(Tp) == 1 &&\n  !std::is_same<Tp, bool>::value &&\n  std::is_integral<Up>::value && sizeof(Up) == 1,\n  Tp*>::type\nunchecked_fill_n(Tp* first, Size n, Up value)\n{\n  if (n > 0)\n  {\n    std::memset(first, (unsigned char)value, (size_t)(n));\n  }\n  return first + n;\n}\n\ntemplate <class OutputIter, class Size, class T>\nOutputIter fill_n(OutputIter first, Size n, const T& value)\n{\n  return unchecked_fill_n(first, n, value);\n}\n\n/*****************************************************************************************/\n// fill\n// 为 [first, last)区间内的所有元素填充新值\n/*****************************************************************************************/\ntemplate <class ForwardIter, class T>\nvoid fill_cat(ForwardIter first, ForwardIter last, const T& value,\n              mystl::forward_iterator_tag)\n{\n  for (; first != last; ++first)\n  {\n    *first = value;\n  }\n}\n\ntemplate <class RandomIter, class T>\nvoid fill_cat(RandomIter first, RandomIter last, const T& value,\n              mystl::random_access_iterator_tag)\n{\n  fill_n(first, last - first, value);\n}\n\ntemplate <class ForwardIter, class T>\nvoid fill(ForwardIter first, ForwardIter last, const T& value)\n{\n  fill_cat(first, last, value, iterator_category(first));\n}\n\n/*****************************************************************************************/\n// lexicographical_compare\n// 以字典序排列对两个序列进行比较，当在某个位置发现第一组不相等元素时，有下列几种情况：\n// (1)如果第一序列的元素较小，返回 true ，否则返回 false\n// (2)如果到达 last1 而尚未到达 last2 返回 true\n// (3)如果到达 last2 而尚未到达 last1 返回 false\n// (4)如果同时到达 last1 和 last2 返回 false\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2>\nbool lexicographical_compare(InputIter1 first1, InputIter1 last1,\n                             InputIter2 first2, InputIter2 last2)\n{\n  for (; first1 != last1 && first2 != last2; ++first1, ++first2)\n  {\n    if (*first1 < *first2)\n      return true;\n    if (*first2 < *first1)\n      return false;\n  }\n  return first1 == last1 && first2 != last2;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class Compred>\nbool lexicographical_compare(InputIter1 first1, InputIter1 last1,\n                             InputIter2 first2, InputIter2 last2, Compred comp)\n{\n  for (; first1 != last1 && first2 != last2; ++first1, ++first2)\n  {\n    if (comp(*first1, *first2))\n      return true;\n    if (comp(*first2, *first1))\n      return false;\n  }\n  return first1 == last1 && first2 != last2;\n}\n\n// 针对 const unsigned char* 的特化版本\nbool lexicographical_compare(const unsigned char* first1,\n                             const unsigned char* last1,\n                             const unsigned char* first2,\n                             const unsigned char* last2)\n{\n  const auto len1 = last1 - first1;\n  const auto len2 = last2 - first2;\n  // 先比较相同长度的部分\n  const auto result = std::memcmp(first1, first2, mystl::min(len1, len2));\n  // 若相等，长度较长的比较大\n  return result != 0 ? result < 0 : len1 < len2;\n}\n\n/*****************************************************************************************/\n// mismatch\n// 平行比较两个序列，找到第一处失配的元素，返回一对迭代器，分别指向两个序列中失配的元素\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2>\nmystl::pair<InputIter1, InputIter2> \nmismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2)\n{\n  while (first1 != last1 && *first1 == *first2)\n  {\n    ++first1;\n    ++first2;\n  }\n  return mystl::pair<InputIter1, InputIter2>(first1, first2);\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class Compred>\nmystl::pair<InputIter1, InputIter2> \nmismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2, Compred comp)\n{\n  while (first1 != last1 && comp(*first1, *first2))\n  {\n    ++first1;\n    ++first2;\n  }\n  return mystl::pair<InputIter1, InputIter2>(first1, first2);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_ALGOBASE_H_\n\n"
  },
  {
    "path": "MyTinySTL/algorithm.h",
    "content": "﻿#ifndef MYTINYSTL_ALGORITHM_H_\n#define MYTINYSTL_ALGORITHM_H_\n\n// 这个头文件包含了 mystl 的所有算法，包括基本算法，数值算法，heap 算法，set 算法和其他算法\n\n#include \"algobase.h\"\n#include \"algo.h\"\n#include \"set_algo.h\"\n#include \"heap_algo.h\"\n#include \"numeric.h\"\n\nnamespace mystl\n{\n\n} // namespace mystl\n\n#endif // !MYTINYSTL_ALGORITHM_H_\n\n"
  },
  {
    "path": "MyTinySTL/alloc.h",
    "content": "#ifndef MYTINYSTL_ALLOC_H_\n#define MYTINYSTL_ALLOC_H_\n\n// 这个头文件包含一个类 alloc，用于分配和回收内存，以内存池的方式实现\n//\n// 从 v2.0.0 版本开始，将不再使用内存池，这个文件将被弃用，但暂时保留\n//\n// 注意！！！\n// 我知道这个文件里很多实现是错的，这是很久很久前写的了，后面已经不用这个东西了，\n// 所以我也没再维护，有诸多问题，已经有人在issue中都提了，free_list的修改，\n// 指针作为参数时没实际修改到原指针，等等。相信会看这么仔细的，大部分都是\n// 初学C++的朋友，大佬都不会看这些玩具了，所以其中的错误，就留给对内存池实现\n// 感兴趣的朋友去修改啦！\n\n#include <new>\n\n#include <cstddef>\n#include <cstdio>\n\nnamespace mystl\n{\n\n// 共用体: FreeList\n// 采用链表的方式管理内存碎片，分配与回收小内存（<=4K）区块\nunion FreeList\n{\n  union FreeList* next;  // 指向下一个区块\n  char data[1];          // 储存本块内存的首地址\n};\n\n// 不同内存范围的上调大小\nenum\n{\n  EAlign128 = 8, \n  EAlign256 = 16, \n  EAlign512 = 32,\n  EAlign1024 = 64, \n  EAlign2048 = 128,\n  EAlign4096 = 256\n};\n\n// 小对象的内存大小\nenum { ESmallObjectBytes = 4096 };\n\n// free lists 个数\nenum { EFreeListsNumber = 56 };\n\n// 空间配置类 alloc\n// 如果内存较大，超过 4096 bytes，直接调用 std::malloc, std::free\n// 当内存较小时，以内存池管理，每次配置一大块内存，并维护对应的自由链表\nclass alloc\n{\nprivate:\n  static char*  start_free;                      // 内存池起始位置\n  static char*  end_free;                        // 内存池结束位置\n  static size_t heap_size;                       // 申请 heap 空间附加值大小\n  \n  static FreeList* free_list[EFreeListsNumber];  // 自由链表\n\npublic:\n  static void* allocate(size_t n);\n  static void  deallocate(void* p, size_t n);\n  static void* reallocate(void* p, size_t old_size, size_t new_size);\n\nprivate:\n  static size_t M_align(size_t bytes);\n  static size_t M_round_up(size_t bytes);\n  static size_t M_freelist_index(size_t bytes);\n  static void*  M_refill(size_t n);\n  static char*  M_chunk_alloc(size_t size, size_t &nobj);\n};\n\n// 静态成员变量初始化\n\nchar*  alloc::start_free = nullptr;\nchar*  alloc::end_free = nullptr;\nsize_t alloc::heap_size = 0;\n\nFreeList* alloc::free_list[EFreeListsNumber] = {\n  nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,\n  nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,\n  nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,\n  nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,\n  nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,\n  nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,\n  nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr\n  };\n\n// 分配大小为 n 的空间， n > 0\ninline void* alloc::allocate(size_t n)\n{\n  FreeList* my_free_list;\n  FreeList* result;\n  if (n > static_cast<size_t>(ESmallObjectBytes))\n    return std::malloc(n);\n  my_free_list = free_list[M_freelist_index(n)];\n  result = my_free_list;\n  if (result == nullptr)\n  {\n    void* r = M_refill(M_round_up(n));\n    return r;\n  }\n  my_free_list = result->next;\n  return result;\n}\n\n// 释放 p 指向的大小为 n 的空间, p 不能为 0\ninline void alloc::deallocate(void* p, size_t n)\n{\n  if (n > static_cast<size_t>(ESmallObjectBytes))\n  {\n    std::free(p);\n    return;\n  }\n  FreeList* q = reinterpret_cast<FreeList*>(p);\n  FreeList* my_free_list;\n  my_free_list = free_list[M_freelist_index(n)];\n  q->next = my_free_list;\n  my_free_list = q;\n}\n\n// 重新分配空间，接受三个参数，参数一为指向新空间的指针，参数二为原来空间的大小，参数三为申请空间的大小\ninline void* alloc::reallocate(void* p, size_t old_size, size_t new_size)\n{\n  deallocate(p, old_size);\n  p = allocate(new_size);\n  return p;\n}\n\n// bytes 对应上调大小\ninline size_t alloc::M_align(size_t bytes)\n{\n  if (bytes <= 512)\n  {\n    return bytes <= 256\n      ? bytes <= 128 ? EAlign128 : EAlign256\n      : EAlign512;\n  }\n  return bytes <= 2048\n    ? bytes <= 1024 ? EAlign1024 : EAlign2048\n    : EAlign4096;\n}\n\n// 将 bytes 上调至对应区间大小\ninline size_t alloc::M_round_up(size_t bytes)\n{\n  return ((bytes + M_align(bytes) - 1) & ~(M_align(bytes) - 1));\n}\n\n// 根据区块大小，选择第 n 个 free lists\ninline size_t alloc::M_freelist_index(size_t bytes)\n{\n  if (bytes <= 512)\n  {\n    return bytes <= 256\n      ? bytes <= 128 \n        ? ((bytes + EAlign128 - 1) / EAlign128 - 1) \n        : (15 + (bytes + EAlign256 - 129) / EAlign256)\n      : (23 + (bytes + EAlign512 - 257) / EAlign512);\n  }\n  return bytes <= 2048\n    ? bytes <= 1024 \n      ? (31 + (bytes + EAlign1024 - 513) / EAlign1024)\n      : (39 + (bytes + EAlign2048 - 1025) / EAlign2048)\n    : (47 + (bytes + EAlign4096 - 2049) / EAlign4096);\n}\n\n// 重新填充 free list\nvoid* alloc::M_refill(size_t n)\n{\n  size_t nblock = 10;\n  char* c = M_chunk_alloc(n, nblock);\n  FreeList* my_free_list;\n  FreeList* result, *cur, *next;\n  // 如果只有一个区块，就把这个区块返回给调用者，free list 没有增加新节点\n  if (nblock == 1)\n    return c;\n  // 否则把一个区块给调用者，剩下的纳入 free list 作为新节点\n  my_free_list = free_list[M_freelist_index(n)];\n  result = (FreeList*)c;\n  my_free_list = next = (FreeList*)(c + n);\n  for (size_t i = 1; ; ++i)\n  {\n    cur = next;\n    next = (FreeList*)((char*)next + n);\n    if (nblock - 1 == i)\n    {\n      cur->next = nullptr;\n      break;\n    }\n    else\n    {\n      cur->next = next;\n    }\n  }\n  return result;\n}\n\n// 从内存池中取空间给 free list 使用，条件不允许时，会调整 nblock\nchar* alloc::M_chunk_alloc(size_t size, size_t& nblock)\n{\n  char* result;\n  size_t need_bytes = size * nblock;\n  size_t pool_bytes = end_free - start_free;\n\n  // 如果内存池剩余大小完全满足需求量，返回它\n  if (pool_bytes >= need_bytes)\n  {\n    result = start_free;\n    start_free += need_bytes;\n    return result;\n  }\n\n  // 如果内存池剩余大小不能完全满足需求量，但至少可以分配一个或一个以上的区块，就返回它\n  else if (pool_bytes >= size)\n  {\n    nblock = pool_bytes / size;\n    need_bytes = size * nblock;\n    result = start_free;\n    start_free += need_bytes;\n    return result;\n  }\n\n  // 如果内存池剩余大小连一个区块都无法满足\n  else\n  {\n    if (pool_bytes > 0)\n    { // 如果内存池还有剩余，把剩余的空间加入到 free list 中\n      FreeList* my_free_list = free_list[M_freelist_index(pool_bytes)];\n      ((FreeList*)start_free)->next = my_free_list;\n      my_free_list = (FreeList*)start_free;\n    }\n    // 申请 heap 空间\n    size_t bytes_to_get = (need_bytes << 1) + M_round_up(heap_size >> 4);\n    start_free = (char*)std::malloc(bytes_to_get);\n    if (!start_free)\n    { // heap 空间也不够\n      FreeList* my_free_list, *p;\n      // 试着查找有无未用区块，且区块足够大的 free list\n      for (size_t i = size; i <= ESmallObjectBytes; i += M_align(i))\n      {\n        my_free_list = free_list[M_freelist_index(i)];\n        p = my_free_list;\n        if (p)\n        {\n          my_free_list = p->next;\n          start_free = (char*)p;\n          end_free = start_free + i;\n          return M_chunk_alloc(size, nblock);\n        }\n      }\n      std::printf(\"out of memory\");\n      end_free = nullptr;\n      throw std::bad_alloc();\n    }\n    end_free = start_free + bytes_to_get;\n    heap_size += bytes_to_get;\n    return M_chunk_alloc(size, nblock);\n  }\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_ALLOC_H_\n\n"
  },
  {
    "path": "MyTinySTL/allocator.h",
    "content": "﻿#ifndef MYTINYSTL_ALLOCATOR_H_\n#define MYTINYSTL_ALLOCATOR_H_\n\n// 这个头文件包含一个模板类 allocator，用于管理内存的分配、释放，对象的构造、析构\n\n#include \"construct.h\"\n#include \"util.h\"\n\nnamespace mystl\n{\n\n// 模板类：allocator\n// 模板函数代表数据类型\ntemplate <class T>\nclass allocator\n{\npublic:\n  typedef T            value_type;\n  typedef T*           pointer;\n  typedef const T*     const_pointer;\n  typedef T&           reference;\n  typedef const T&     const_reference;\n  typedef size_t       size_type;\n  typedef ptrdiff_t    difference_type;\n\npublic:\n  static T*   allocate();\n  static T*   allocate(size_type n);\n\n  static void deallocate(T* ptr);\n  static void deallocate(T* ptr, size_type n);\n\n  static void construct(T* ptr);\n  static void construct(T* ptr, const T& value);\n  static void construct(T* ptr, T&& value);\n\n  template <class... Args>\n  static void construct(T* ptr, Args&& ...args);\n\n  static void destroy(T* ptr);\n  static void destroy(T* first, T* last);\n};\n\ntemplate <class T>\nT* allocator<T>::allocate()\n{\n  return static_cast<T*>(::operator new(sizeof(T)));\n}\n\ntemplate <class T>\nT* allocator<T>::allocate(size_type n)\n{\n  if (n == 0)\n    return nullptr;\n  return static_cast<T*>(::operator new(n * sizeof(T)));\n}\n\ntemplate <class T>\nvoid allocator<T>::deallocate(T* ptr)\n{\n  if (ptr == nullptr)\n    return;\n  ::operator delete(ptr);\n}\n\ntemplate <class T>\nvoid allocator<T>::deallocate(T* ptr, size_type /*size*/)\n{\n  if (ptr == nullptr)\n    return;\n  ::operator delete(ptr);\n}\n\ntemplate <class T>\nvoid allocator<T>::construct(T* ptr)\n{\n  mystl::construct(ptr);\n}\n\ntemplate <class T>\nvoid allocator<T>::construct(T* ptr, const T& value)\n{\n  mystl::construct(ptr, value);\n}\n\ntemplate <class T>\n void allocator<T>::construct(T* ptr, T&& value)\n{\n  mystl::construct(ptr, mystl::move(value));\n}\n\ntemplate <class T>\ntemplate <class ...Args>\n void allocator<T>::construct(T* ptr, Args&& ...args)\n{\n  mystl::construct(ptr, mystl::forward<Args>(args)...);\n}\n\ntemplate <class T>\nvoid allocator<T>::destroy(T* ptr)\n{\n  mystl::destroy(ptr);\n}\n\ntemplate <class T>\nvoid allocator<T>::destroy(T* first, T* last)\n{\n  mystl::destroy(first, last);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_ALLOCATOR_H_\n\n"
  },
  {
    "path": "MyTinySTL/astring.h",
    "content": "﻿#ifndef MYTINYSTL_ASTRING_H_\n#define MYTINYSTL_ASTRING_H_\n\n// 定义了 string, wstring, u16string, u32string 类型\n\n#include \"basic_string.h\"\n\nnamespace mystl\n{\n\nusing string    = mystl::basic_string<char>;\nusing wstring   = mystl::basic_string<wchar_t>;\nusing u16string = mystl::basic_string<char16_t>;\nusing u32string = mystl::basic_string<char32_t>;\n\n}\n#endif // !MYTINYSTL_ASTRING_H_\n\n"
  },
  {
    "path": "MyTinySTL/basic_string.h",
    "content": "﻿#ifndef MYTINYSTL_BASIC_STRING_H_\n#define MYTINYSTL_BASIC_STRING_H_\n\n// 这个头文件包含一个模板类 basic_string\n// 用于表示字符串类型\n\n#include <iostream>\n\n#include \"iterator.h\"\n#include \"memory.h\"\n#include \"functional.h\"\n#include \"exceptdef.h\"\n\nnamespace mystl\n{\n\n// char_traits\n\ntemplate <class CharType>\nstruct char_traits\n{\n  typedef CharType char_type;\n  \n  static size_t length(const char_type* str)\n  {\n    size_t len = 0;\n    for (; *str != char_type(0); ++str)\n      ++len;\n    return len;\n  }\n\n  static int compare(const char_type* s1, const char_type* s2, size_t n)\n  {\n    for (; n != 0; --n, ++s1, ++s2)\n    {\n      if (*s1 < *s2)\n        return -1;\n      if (*s2 < *s1)\n        return 1;\n    }\n    return 0;\n  }\n\n  static char_type* copy(char_type* dst, const char_type* src, size_t n)\n  {\n    MYSTL_DEBUG(src + n <= dst || dst + n <= src);\n    char_type* r = dst;\n    for (; n != 0; --n, ++dst, ++src)\n      *dst = *src;\n    return r;\n  }\n\n  static char_type* move(char_type* dst, const char_type* src, size_t n)\n  {\n    char_type* r = dst;\n    if (dst < src)\n    {\n      for (; n != 0; --n, ++dst, ++src)\n        *dst = *src;\n    }\n    else if (src < dst)\n    {\n      dst += n;\n      src += n;\n      for (; n != 0; --n)\n        *--dst = *--src;\n    }\n    return r;\n  }\n\n  static char_type* fill(char_type* dst, char_type ch, size_t count)\n  {\n    char_type* r = dst;\n    for (; count > 0; --count, ++dst)\n      *dst = ch;\n    return r;\n  }\n};\n\n// Partialized. char_traits<char>\ntemplate <> \nstruct char_traits<char>\n{\n  typedef char char_type;\n\n  static size_t length(const char_type* str) noexcept\n  { return std::strlen(str); }\n\n  static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept\n  { return std::memcmp(s1, s2, n); }\n\n  static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    MYSTL_DEBUG(src + n <= dst || dst + n <= src);\n    return static_cast<char_type*>(std::memcpy(dst, src, n));\n  }\n\n  static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    return static_cast<char_type*>(std::memmove(dst, src, n));\n  }\n\n  static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept\n  { \n    return static_cast<char_type*>(std::memset(dst, ch, count));\n  }\n};\n\n// Partialized. char_traits<wchar_t>\ntemplate <>\nstruct char_traits<wchar_t>\n{\n  typedef wchar_t char_type;\n\n  static size_t length(const char_type* str) noexcept\n  {\n    return std::wcslen(str);\n  }\n\n  static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept\n  {\n    return std::wmemcmp(s1, s2, n);\n  }\n\n  static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    MYSTL_DEBUG(src + n <= dst || dst + n <= src);\n    return static_cast<char_type*>(std::wmemcpy(dst, src, n));\n  }\n\n  static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    return static_cast<char_type*>(std::wmemmove(dst, src, n));\n  }\n\n  static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept\n  { \n    return static_cast<char_type*>(std::wmemset(dst, ch, count));\n  }\n};\n\n// Partialized. char_traits<char16_t>\ntemplate <>\nstruct char_traits<char16_t>\n{\n  typedef char16_t char_type;\n\n  static size_t length(const char_type* str) noexcept\n  {\n    size_t len = 0;\n    for (; *str != char_type(0); ++str)\n      ++len;\n    return len;\n  }\n\n  static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept\n  {\n    for (; n != 0; --n, ++s1, ++s2)\n    {\n      if (*s1 < *s2)\n        return -1;\n      if (*s2 < *s1)\n        return 1;\n    }\n    return 0;\n  }\n\n  static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    MYSTL_DEBUG(src + n <= dst || dst + n <= src);\n    char_type* r = dst;\n    for (; n != 0; --n, ++dst, ++src)\n      *dst = *src;\n    return r;\n  }\n\n  static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    char_type* r = dst;\n    if (dst < src)\n    {\n      for (; n != 0; --n, ++dst, ++src)\n        *dst = *src;\n    }\n    else if (src < dst)\n    {\n      dst += n;\n      src += n;\n      for (; n != 0; --n)\n        *--dst = *--src;\n    }\n    return r;\n  }\n\n  static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept\n  {\n    char_type* r = dst;\n    for (; count > 0; --count, ++dst)\n      *dst = ch;\n    return r;\n  }\n};\n\n// Partialized. char_traits<char32_t>\ntemplate <>\nstruct char_traits<char32_t>\n{\n  typedef char32_t char_type;\n\n  static size_t length(const char_type* str) noexcept\n  {\n    size_t len = 0;\n    for (; *str != char_type(0); ++str)\n      ++len;\n    return len;\n  }\n\n  static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept\n  {\n    for (; n != 0; --n, ++s1, ++s2)\n    {\n      if (*s1 < *s2)\n        return -1;\n      if (*s2 < *s1)\n        return 1;\n    }\n    return 0;\n  }\n\n  static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    MYSTL_DEBUG(src + n <= dst || dst + n <= src);\n    char_type* r = dst;\n    for (; n != 0; --n, ++dst, ++src)\n      *dst = *src;\n    return r;\n  }\n\n  static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept\n  {\n    char_type* r = dst;\n    if (dst < src)\n    {\n      for (; n != 0; --n, ++dst, ++src)\n        *dst = *src;\n    }\n    else if (src < dst)\n    {\n      dst += n;\n      src += n;\n      for (; n != 0; --n)\n        *--dst = *--src;\n    }\n    return r;\n  }\n\n  static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept\n  {\n    char_type* r = dst;\n    for (; count > 0; --count, ++dst)\n      *dst = ch;\n    return r;\n  }\n};\n\n// 初始化 basic_string 尝试分配的最小 buffer 大小，可能被忽略\n#define STRING_INIT_SIZE 32\n\n// 模板类 basic_string\n// 参数一代表字符类型，参数二代表萃取字符类型的方式，缺省使用 mystl::char_traits\ntemplate <class CharType, class CharTraits = mystl::char_traits<CharType>>\nclass basic_string\n{\npublic:\n  typedef CharTraits                               traits_type;\n  typedef CharTraits                               char_traits;\n\n  typedef mystl::allocator<CharType>               allocator_type;\n  typedef mystl::allocator<CharType>               data_allocator;\n\n  typedef typename allocator_type::value_type      value_type;\n  typedef typename allocator_type::pointer         pointer;\n  typedef typename allocator_type::const_pointer   const_pointer;\n  typedef typename allocator_type::reference       reference;\n  typedef typename allocator_type::const_reference const_reference;\n  typedef typename allocator_type::size_type       size_type;\n  typedef typename allocator_type::difference_type difference_type;\n\n  typedef value_type*                              iterator;\n  typedef const value_type*                        const_iterator;\n  typedef mystl::reverse_iterator<iterator>        reverse_iterator;\n  typedef mystl::reverse_iterator<const_iterator>  const_reverse_iterator;\n\n  allocator_type get_allocator() { return allocator_type(); }\n\n  static_assert(std::is_pod<CharType>::value, \"Character type of basic_string must be a POD\");\n  static_assert(std::is_same<CharType, typename traits_type::char_type>::value,\n                \"CharType must be same as traits_type::char_type\");\n\npublic:\n  // 末尾位置的值，例:\n  // if (str.find('a') != string::npos) { /* do something */ }\n  static constexpr size_type npos = static_cast<size_type>(-1);\n\nprivate:\n  iterator  buffer_;  // 储存字符串的起始位置\n  size_type size_;    // 大小\n  size_type cap_;     // 容量\n\npublic:\n  // 构造、复制、移动、析构函数\n\n  basic_string() noexcept\n  { try_init(); }\n\n  basic_string(size_type n, value_type ch)\n    :buffer_(nullptr), size_(0), cap_(0)\n  {\n    fill_init(n, ch);\n  }\n\n  basic_string(const basic_string& other, size_type pos)\n    :buffer_(nullptr), size_(0), cap_(0)\n  {\n    init_from(other.buffer_, pos, other.size_ - pos);\n  }\n  basic_string(const basic_string& other, size_type pos, size_type count)\n    :buffer_(nullptr), size_(0), cap_(0)\n  {\n    init_from(other.buffer_, pos, count);\n  }\n\n  basic_string(const_pointer str)\n    :buffer_(nullptr), size_(0), cap_(0)\n  {\n    init_from(str, 0, char_traits::length(str));\n  }\n  basic_string(const_pointer str, size_type count)\n    :buffer_(nullptr), size_(0), cap_(0)\n  {\n    init_from(str, 0, count);\n  }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  basic_string(Iter first, Iter last)\n  { copy_init(first, last, iterator_category(first)); }\n\n  basic_string(const basic_string& rhs) \n    :buffer_(nullptr), size_(0), cap_(0)\n  {\n    init_from(rhs.buffer_, 0, rhs.size_);\n  }\n  basic_string(basic_string&& rhs) noexcept\n    :buffer_(rhs.buffer_), size_(rhs.size_), cap_(rhs.cap_)\n  {\n    rhs.buffer_ = nullptr;\n    rhs.size_ = 0;\n    rhs.cap_ = 0;\n  }\n\n  basic_string& operator=(const basic_string& rhs);\n  basic_string& operator=(basic_string&& rhs) noexcept;\n\n  basic_string& operator=(const_pointer str);\n  basic_string& operator=(value_type ch);\n\n  ~basic_string() { destroy_buffer(); }\n\npublic:\n  // 迭代器相关操作\n  iterator               begin()         noexcept\n  { return buffer_; }\n  const_iterator         begin()   const noexcept\n  { return buffer_; }\n  iterator               end()           noexcept\n  { return buffer_ + size_; }\n  const_iterator         end()     const noexcept\n  { return buffer_ + size_; }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return const_reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return const_reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关操作\n  bool      empty()    const noexcept\n  { return size_ == 0; }\n\n  size_type size()     const noexcept\n  { return size_; }\n  size_type length()   const noexcept\n  { return size_; }\n  size_type capacity() const noexcept\n  { return cap_; }\n  size_type max_size() const noexcept\n  { return static_cast<size_type>(-1); }\n\n  void      reserve(size_type n);\n  void      shrink_to_fit();\n\n  // 访问元素相关操作\n  reference       operator[](size_type n) \n  {\n    MYSTL_DEBUG(n <= size_);\n    if (n == size_)\n      *(buffer_ + n) = value_type();\n    return *(buffer_ + n); \n  }\n  const_reference operator[](size_type n) const\n  { \n    MYSTL_DEBUG(n <= size_);\n    if (n == size_)\n      *(buffer_ + n) = value_type();\n    return *(buffer_ + n);\n  }\n\n  reference       at(size_type n) \n  { \n    THROW_OUT_OF_RANGE_IF(n >= size_, \"basic_string<Char, Traits>::at()\"\n                          \"subscript out of range\");\n    return (*this)[n]; \n  }\n  const_reference at(size_type n) const \n  {\n    THROW_OUT_OF_RANGE_IF(n >= size_, \"basic_string<Char, Traits>::at()\"\n                          \"subscript out of range\");\n    return (*this)[n]; \n  }\n\n  reference       front() \n  { \n    MYSTL_DEBUG(!empty());\n    return *begin(); \n  }\n  const_reference front() const \n  { \n    MYSTL_DEBUG(!empty());\n    return *begin(); \n  }\n\n  reference       back() \n  {\n    MYSTL_DEBUG(!empty()); \n    return *(end() - 1); \n  }\n  const_reference back()  const\n  {\n    MYSTL_DEBUG(!empty()); \n    return *(end() - 1);\n  }\n\n  const_pointer   data()  const noexcept\n  { return to_raw_pointer(); }\n  const_pointer   c_str() const noexcept\n  { return to_raw_pointer(); }\n\n  // 添加删除相关操作\n\n  // insert\n  iterator insert(const_iterator pos, value_type ch);\n  iterator insert(const_iterator pos, size_type count, value_type ch);\n\n  template <class Iter>\n  iterator insert(const_iterator pos, Iter first, Iter last);\n\n\n  // push_back / pop_back\n  void     push_back(value_type ch)\n  { append(1, ch); }\n  void     pop_back()\n  {\n    MYSTL_DEBUG(!empty());\n    --size_;\n  }\n\n  // append\n  basic_string& append(size_type count, value_type ch);\n\n  basic_string& append(const basic_string& str)\n  { return append(str, 0, str.size_); }\n  basic_string& append(const basic_string& str, size_type pos)\n  { return append(str, pos, str.size_ - pos); }\n  basic_string& append(const basic_string& str, size_type pos, size_type count);\n\n  basic_string& append(const_pointer s)\n  { return append(s, char_traits::length(s)); }\n  basic_string& append(const_pointer s, size_type count);\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  basic_string& append(Iter first, Iter last)\n  { return append_range(first, last); }\n\n  // erase /clear\n  iterator erase(const_iterator pos);\n  iterator erase(const_iterator first, const_iterator last);\n\n  // resize\n  void resize(size_type count)\n  { resize(count, value_type()); }\n  void resize(size_type count, value_type ch);\n\n  void     clear() noexcept\n  { size_ = 0; }\n\n  // basic_string 相关操作\n\n  // compare\n  int compare(const basic_string& other) const;\n  int compare(size_type pos1, size_type count1, const basic_string& other) const;\n  int compare(size_type pos1, size_type count1, const basic_string& other,\n              size_type pos2, size_type count2 = npos) const;\n  int compare(const_pointer s) const;\n  int compare(size_type pos1, size_type count1, const_pointer s) const;\n  int compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const;\n\n  // substr\n  basic_string substr(size_type index, size_type count = npos)\n  {\n    count = mystl::min(count, size_ - index);\n    return basic_string(buffer_ + index, buffer_ + index + count);\n  }\n\n  // replace\n  basic_string& replace(size_type pos, size_type count, const basic_string& str)\n  {\n    THROW_OUT_OF_RANGE_IF(pos > size_, \"basic_string<Char, Traits>::replace's pos out of range\");\n    return replace_cstr(buffer_ + pos, count, str.buffer_, str.size_);\n  }\n  basic_string& replace(const_iterator first, const_iterator last, const basic_string& str)\n  {\n    MYSTL_DEBUG(begin() <= first && last <= end() && first <= last);\n    return replace_cstr(first, static_cast<size_type>(last - first), str.buffer_, str.size_);\n  }\n\n  basic_string& replace(size_type pos, size_type count, const_pointer str)\n  {\n    THROW_OUT_OF_RANGE_IF(pos > size_, \"basic_string<Char, Traits>::replace's pos out of range\");\n    return replace_cstr(buffer_ + pos, count, str, char_traits::length(str));\n  }\n  basic_string& replace(const_iterator first, const_iterator last, const_pointer str)\n  {\n    MYSTL_DEBUG(begin() <= first && last <= end() && first <= last);\n    return replace_cstr(first, static_cast<size_type>(last - first), str, char_traits::length(str));\n  }\n\n  basic_string& replace(size_type pos, size_type count, const_pointer str, size_type count2)\n  {\n    THROW_OUT_OF_RANGE_IF(pos > size_, \"basic_string<Char, Traits>::replace's pos out of range\");\n    return replace_cstr(buffer_ + pos, count, str, count2);\n  }\n  basic_string& replace(const_iterator first, const_iterator last, const_pointer str, size_type count)\n  {\n    MYSTL_DEBUG(begin() <= first && last <= end() && first <= last);\n    return replace_cstr(first, static_cast<size_type>(last - first), str, count);\n\n  }\n\n  basic_string& replace(size_type pos, size_type count, size_type count2, value_type ch)\n  {\n    THROW_OUT_OF_RANGE_IF(pos > size_, \"basic_string<Char, Traits>::replace's pos out of range\");\n    return replace_fill(buffer_ + pos, count, count2, ch);\n  }\n  basic_string& replace(const_iterator first, const_iterator last, size_type count, value_type ch)\n  {\n    MYSTL_DEBUG(begin() <= first && last <= end() && first <= last);\n    return replace_fill(first, static_cast<size_type>(last - first), count, ch);\n  }\n\n  basic_string& replace(size_type pos1, size_type count1, const basic_string& str,\n                        size_type pos2, size_type count2 = npos)\n  {\n    THROW_OUT_OF_RANGE_IF(pos1 > size_ || pos2 > str.size_,\n                          \"basic_string<Char, Traits>::replace's pos out of range\");\n    return replace_cstr(buffer_ + pos1, count1, str.buffer_ + pos2, count2);\n  }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  basic_string& replace(const_iterator first, const_iterator last, Iter first2, Iter last2)\n  {\n    MYSTL_DEBUG(begin() <= first && last <= end() && first <= last);\n    return replace_copy(first, last, first2, last2);\n  }\n\n  // reverse\n  void reverse() noexcept;\n\n  // swap\n  void swap(basic_string& rhs) noexcept;\n\n  // 查找相关操作\n\n  // find\n  size_type find(value_type ch, size_type pos = 0)                             const noexcept;\n  size_type find(const_pointer str, size_type pos = 0)                         const noexcept;\n  size_type find(const_pointer str, size_type pos, size_type count)            const noexcept;\n  size_type find(const basic_string& str, size_type pos = 0)                   const noexcept;\n\n  // rfind\n  size_type rfind(value_type ch, size_type pos = npos)                         const noexcept;\n  size_type rfind(const_pointer str, size_type pos = npos)                     const noexcept;\n  size_type rfind(const_pointer str, size_type pos, size_type count)           const noexcept;\n  size_type rfind(const basic_string& str, size_type pos = npos)               const noexcept;\n\n  // find_first_of\n  size_type find_first_of(value_type ch, size_type pos = 0)                    const noexcept;\n  size_type find_first_of(const_pointer s, size_type pos = 0)                  const noexcept;\n  size_type find_first_of(const_pointer s, size_type pos, size_type count)     const noexcept;\n  size_type find_first_of(const basic_string& str, size_type pos = 0)          const noexcept;\n\n  // find_first_not_of\n  size_type find_first_not_of(value_type ch, size_type pos = 0)                const noexcept;\n  size_type find_first_not_of(const_pointer s, size_type pos = 0)              const noexcept;\n  size_type find_first_not_of(const_pointer s, size_type pos, size_type count) const noexcept;\n  size_type find_first_not_of(const basic_string& str, size_type pos = 0)      const noexcept;\n\n  // find_last_of\n  size_type find_last_of(value_type ch, size_type pos = 0)                     const noexcept;\n  size_type find_last_of(const_pointer s, size_type pos = 0)                   const noexcept;\n  size_type find_last_of(const_pointer s, size_type pos, size_type count)      const noexcept;\n  size_type find_last_of(const basic_string& str, size_type pos = 0)           const noexcept;\n\n  // find_last_not_of\n  size_type find_last_not_of(value_type ch, size_type pos = 0)                 const noexcept;\n  size_type find_last_not_of(const_pointer s, size_type pos = 0)               const noexcept;\n  size_type find_last_not_of(const_pointer s, size_type pos, size_type count)  const noexcept;\n  size_type find_last_not_of(const basic_string& str, size_type pos = 0)       const noexcept;\n\n  // count\n  size_type count(value_type ch, size_type pos = 0) const noexcept;\n\npublic:\n  // 重载 operator+= \n  basic_string& operator+=(const basic_string& str)\n  { return append(str); }\n  basic_string& operator+=(value_type ch)\n  { return append(1, ch); }\n  basic_string& operator+=(const_pointer str)\n  { return append(str, str + char_traits::length(str)); }\n\n  // 重载 operator >> / operatror <<\n\n  friend std::istream& operator >> (std::istream& is, basic_string& str)\n  {\n    value_type* buf = new value_type[4096];\n    is >> buf;\n    basic_string tmp(buf);\n    str = std::move(tmp);\n    delete[]buf;\n    return is;\n  }\n\n  friend std::ostream& operator << (std::ostream& os, const basic_string& str)\n  {\n    for (size_type i = 0; i < str.size_; ++i)\n      os << *(str.buffer_ + i);\n    return os;\n  }\n\nprivate:\n  // helper functions\n\n  // init / destroy \n  void          try_init() noexcept;\n\n  void          fill_init(size_type n, value_type ch);\n\n  template <class Iter>\n  void          copy_init(Iter first, Iter last, mystl::input_iterator_tag);\n  template <class Iter>\n  void          copy_init(Iter first, Iter last, mystl::forward_iterator_tag);\n\n  void          init_from(const_pointer src, size_type pos, size_type n);\n\n  void          destroy_buffer();\n\n  // get raw pointer\n  const_pointer to_raw_pointer() const;\n\n  // shrink_to_fit\n  void          reinsert(size_type size);\n\n  // append\n  template <class Iter>\n  basic_string& append_range(Iter first, Iter last);\n\n  // compare\n  int compare_cstr(const_pointer s1, size_type n1, const_pointer s2, size_type n2) const;\n\n  // replace\n  basic_string& replace_cstr(const_iterator first, size_type count1, const_pointer str, size_type count2);\n  basic_string& replace_fill(const_iterator first, size_type count1, size_type count2, value_type ch);\n  template <class Iter>\n  basic_string& replace_copy(const_iterator first, const_iterator last, Iter first2, Iter last2);\n\n  // reallocate\n  void          reallocate(size_type need);\n  iterator      reallocate_and_fill(iterator pos, size_type n, value_type ch);\n  iterator      reallocate_and_copy(iterator pos, const_iterator first, const_iterator last);\n};\n\n/*****************************************************************************************/\n\n// 复制赋值操作符\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>&\nbasic_string<CharType, CharTraits>::\noperator=(const basic_string& rhs)\n{\n  if (this != &rhs)\n  {\n    basic_string tmp(rhs);\n    swap(tmp);\n  }\n  return *this;\n}\n\n// 移动赋值操作符\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>&\nbasic_string<CharType, CharTraits>::\noperator=(basic_string&& rhs) noexcept\n{\n  destroy_buffer();\n  buffer_ = rhs.buffer_;\n  size_ = rhs.size_;\n  cap_ = rhs.cap_;\n  rhs.buffer_ = nullptr;\n  rhs.size_ = 0;\n  rhs.cap_ = 0;\n  return *this;\n}\n\n// 用一个字符串赋值\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>&\nbasic_string<CharType, CharTraits>::\noperator=(const_pointer str)\n{\n  const size_type len = char_traits::length(str);\n  if (cap_ < len)\n  {\n    auto new_buffer = data_allocator::allocate(len + 1);\n    data_allocator::deallocate(buffer_);\n    buffer_ = new_buffer;\n    cap_ = len + 1;\n  }\n  char_traits::copy(buffer_, str, len);\n  size_ = len;\n  return *this;\n}\n\n// 用一个字符赋值\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>&\nbasic_string<CharType, CharTraits>::\noperator=(value_type ch)\n{\n  if (cap_ < 1)\n  {\n    auto new_buffer = data_allocator::allocate(2);\n    data_allocator::deallocate(buffer_);\n    buffer_ = new_buffer;\n    cap_ = 2;\n  }\n  *buffer_ = ch;\n  size_ = 1;\n  return *this;\n}\n\n// 预留储存空间\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nreserve(size_type n)\n{\n  if (cap_ < n)\n  {\n    THROW_LENGTH_ERROR_IF(n > max_size(), \"n can not larger than max_size()\"\n                          \"in basic_string<Char,Traits>::reserve(n)\");\n    auto new_buffer = data_allocator::allocate(n);\n    char_traits::move(new_buffer, buffer_, size_);\n    buffer_ = new_buffer;\n    cap_ = n;\n  }\n}\n\n// 减少不用的空间\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nshrink_to_fit()\n{\n  if (size_ != cap_)\n  {\n    reinsert(size_);\n  }\n}\n\n// 在 pos 处插入一个元素\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::iterator\nbasic_string<CharType, CharTraits>::\ninsert(const_iterator pos, value_type ch)\n{\n  iterator r = const_cast<iterator>(pos);\n  if (size_ == cap_)\n  {\n    return reallocate_and_fill(r, 1, ch);\n  }\n  char_traits::move(r + 1, r, end() - r);\n  ++size_;\n  *r = ch;\n  return r;\n}\n\n// 在 pos 处插入 n 个元素\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::iterator\nbasic_string<CharType, CharTraits>::\ninsert(const_iterator pos, size_type count, value_type ch)\n{\n  iterator r = const_cast<iterator>(pos);\n  if (count == 0)\n    return r;\n  if (cap_ - size_ < count)\n  {\n    return reallocate_and_fill(r, count, ch);\n  }\n  if (pos == end())\n  {\n    char_traits::fill(end(), ch, count);\n    size_ += count;\n    return r;\n  }\n  char_traits::move(r + count, r, count);\n  char_traits::fill(r, ch, count);\n  size_ += count;\n  return r;\n}\n\n// 在 pos 处插入 [first, last) 内的元素\ntemplate <class CharType, class CharTraits>\ntemplate <class Iter>\ntypename basic_string<CharType, CharTraits>::iterator\nbasic_string<CharType, CharTraits>::\ninsert(const_iterator pos, Iter first, Iter last)\n{\n  iterator r = const_cast<iterator>(pos);\n  const size_type len = mystl::distance(first, last);\n  if (len == 0)\n    return r;\n  if (cap_ - size_ < len)\n  {\n    return reallocate_and_copy(r, first, last);\n  }\n  if (pos == end())\n  {\n    mystl::uninitialized_copy(first, last, end());\n    size_ += len;\n    return r;\n  }\n  char_traits::move(r + len, r, len);\n  mystl::uninitialized_copy(first, last, r);\n  size_ += len;\n  return r;\n}\n\n// 在末尾添加 count 个 ch\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>& \nbasic_string<CharType, CharTraits>::\nappend(size_type count, value_type ch)\n{\n  THROW_LENGTH_ERROR_IF(size_ > max_size() - count,\n                        \"basic_string<Char, Tratis>'s size too big\");\n  if (cap_ - size_ < count)\n  {\n    reallocate(count);\n  }\n  char_traits::fill(buffer_ + size_, ch, count);\n  size_ += count;\n  return *this;\n}\n\n// 在末尾添加 [str[pos] str[pos+count]) 一段\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>& \nbasic_string<CharType, CharTraits>::\nappend(const basic_string& str, size_type pos, size_type count)\n{\n  THROW_LENGTH_ERROR_IF(size_ > max_size() - count,\n                        \"basic_string<Char, Tratis>'s size too big\");\n  if (count == 0)\n    return *this;\n  if (cap_ - size_ < count)\n  {\n    reallocate(count);\n  }\n  char_traits::copy(buffer_ + size_, str.buffer_ + pos, count);\n  size_ += count;\n  return *this;\n}\n\n// 在末尾添加 [s, s+count) 一段\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>& \nbasic_string<CharType, CharTraits>::\nappend(const_pointer s, size_type count)\n{\n  THROW_LENGTH_ERROR_IF(size_ > max_size() - count,\n                        \"basic_string<Char, Tratis>'s size too big\");\n  if (cap_ - size_ < count)\n  {\n    reallocate(count);\n  }\n  char_traits::copy(buffer_ + size_, s, count);\n  size_ += count;\n  return *this;\n}\n\n// 删除 pos 处的元素\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::iterator\nbasic_string<CharType, CharTraits>::\nerase(const_iterator pos)\n{\n  MYSTL_DEBUG(pos != end());\n  iterator r = const_cast<iterator>(pos);\n  char_traits::move(r, pos + 1, end() - pos - 1);\n  --size_;\n  return r;\n}\n\n// 删除 [first, last) 的元素\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::iterator\nbasic_string<CharType, CharTraits>::\nerase(const_iterator first, const_iterator last)\n{\n  if (first == begin() && last == end())\n  {\n    clear();\n    return end();\n  }\n  const size_type n = end() - last;\n  iterator r = const_cast<iterator>(first);\n  char_traits::move(r, last, n);\n  size_ -= (last - first);\n  return r;\n}\n\n// 重置容器大小\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nresize(size_type count, value_type ch)\n{\n  if (count < size_)\n  {\n    erase(buffer_ + count, buffer_ + size_);\n  }\n  else\n  {\n    append(count - size_, ch);\n  }\n}\n\n// 比较两个 basic_string，小于返回 -1，大于返回 1，等于返回 0\ntemplate <class CharType, class CharTraits>\nint basic_string<CharType, CharTraits>::\ncompare(const basic_string& other) const\n{\n  return compare_cstr(buffer_, size_, other.buffer_, other.size_);\n}\n\n// 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 比较\ntemplate <class CharType, class CharTraits>\nint basic_string<CharType, CharTraits>::\ncompare(size_type pos1, size_type count1, const basic_string& other) const\n{\n  auto n1 = mystl::min(count1, size_ - pos1);\n  return compare_cstr(buffer_ + pos1, n1, other.buffer_, other.size_);\n}\n\n// 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 下标 pos2 开始的 count2 个字符比较\ntemplate <class CharType, class CharTraits>\nint basic_string<CharType, CharTraits>::\ncompare(size_type pos1, size_type count1, const basic_string& other,\n        size_type pos2, size_type count2) const\n{\n  auto n1 = mystl::min(count1, size_ - pos1);\n  auto n2 = mystl::min(count2, other.size_ - pos2);\n  return compare_cstr(buffer_, n1, other.buffer_, n2);\n}\n\n// 跟一个字符串比较\ntemplate <class CharType, class CharTraits>\nint basic_string<CharType, CharTraits>::\ncompare(const_pointer s) const\n{\n  auto n2 = char_traits::length(s);\n  return compare_cstr(buffer_, size_, s, n2);\n}\n\n// 从下标 pos1 开始的 count1 个字符跟另一个字符串比较\ntemplate <class CharType, class CharTraits>\nint basic_string<CharType, CharTraits>::\ncompare(size_type pos1, size_type count1, const_pointer s) const\n{\n  auto n1 = mystl::min(count1, size_ - pos1);\n  auto n2 = char_traits::length(s);\n  return compare_cstr(buffer_, n1, s, n2);\n}\n\n// 从下标 pos1 开始的 count1 个字符跟另一个字符串的前 count2 个字符比较\ntemplate <class CharType, class CharTraits>\nint basic_string<CharType, CharTraits>::\ncompare(size_type pos1, size_type count1, const_pointer s, size_type count2) const\n{\n  auto n1 = mystl::min(count1, size_ - pos1);\n  return compare_cstr(buffer_, n1, s, count2);\n}\n\n// 反转 basic_string\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nreverse() noexcept\n{\n  for (auto i = begin(), j = end(); i < j;)\n  {\n    mystl::iter_swap(i++, --j);\n  }\n}\n\n// 交换两个 basic_string\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nswap(basic_string& rhs) noexcept\n{\n  if (this != &rhs)\n  {\n    mystl::swap(buffer_, rhs.buffer_);\n    mystl::swap(size_, rhs.size_);\n    mystl::swap(cap_, rhs.cap_);\n  }\n}\n\n// 从下标 pos 开始查找字符为 ch 的元素，若找到返回其下标，否则返回 npos\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind(value_type ch, size_type pos) const noexcept\n{\n  for (auto i = pos; i < size_; ++i)\n  {\n    if (*(buffer_ + i) == ch)\n      return i;\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找字符串 str，若找到返回起始位置的下标，否则返回 npos\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind(const_pointer str, size_type pos) const noexcept\n{\n  const auto len = char_traits::length(str);\n  if (len == 0)\n    return pos;\n  if (size_ - pos < len)\n    return npos;\n  const auto left = size_ - len;\n  for (auto i = pos; i <= left; ++i)\n  {\n    if (*(buffer_ + i) == *str)\n    {\n      size_type j = 1;\n      for (; j < len; ++j)\n      {\n        if (*(buffer_ + i + j) != *(str + j))\n          break;\n      }\n      if (j == len)\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找字符串 str 的前 count 个字符，若找到返回起始位置的下标，否则返回 npos\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind(const_pointer str, size_type pos, size_type count) const noexcept\n{\n  if (count == 0)\n    return pos;\n  if (size_ - pos < count)\n    return npos;\n  const auto left = size_ - count;\n  for (auto i = pos; i <= left; ++i)\n  {\n    if (*(buffer_ + i) == *str)\n    {\n      size_type j = 1;\n      for (; j < count; ++j)\n      {\n        if (*(buffer_ + i + j) != *(str + j))\n          break;\n      }\n      if (j == count)\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找字符串 str，若找到返回起始位置的下标，否则返回 npos\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind(const basic_string& str, size_type pos) const noexcept\n{\n  const size_type count = str.size_;\n  if (count == 0)\n    return pos;\n  if (size_ - pos < count)\n    return npos;\n  const auto left = size_ - count;\n  for (auto i = pos; i <= left; ++i)\n  {\n    if (*(buffer_ + i) == str.front())\n    {\n      size_type j = 1;\n      for (; j < count; ++j)\n      {\n        if (*(buffer_ + i + j) != str[j])\n          break;\n      }\n      if (j == count)\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始反向查找值为 ch 的元素，与 find 类似\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nrfind(value_type ch, size_type pos) const noexcept\n{\n  if (pos >= size_)\n    pos = size_ - 1;\n  for (auto i = pos; i != 0; --i)\n  {\n    if (*(buffer_ + i) == ch)\n      return i;\n  }\n  return front() == ch ? 0 : npos;\n}\n\n// 从下标 pos 开始反向查找字符串 str，与 find 类似\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nrfind(const_pointer str, size_type pos) const noexcept\n{\n  if (pos >= size_)\n    pos = size_ - 1;\n  const size_type len = char_traits::length(str);\n  switch (len)\n  {\n    case 0: \n      return pos;\n    case 1: \n    {\n      for (auto i = pos; i != 0; --i)\n      {\n        if (*(buffer_ + i) == *str)\n          return i;\n      }\n      return front() == *str ? 0 : npos;\n    }\n    default:\n    { // len >= 2\n      for (auto i = pos; i >= len - 1; --i)\n      {\n        if (*(buffer_ + i) == *(str + len - 1))\n        {\n          size_type j = 1;\n          for (; j < len; ++j)\n          {\n            if (*(buffer_ + i - j) != *(str + len - j - 1))\n              break;\n          }\n          if (j == len)\n            return i - len + 1;\n        }\n      }\n      break;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始反向查找字符串 str 前 count 个字符，与 find 类似\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nrfind(const_pointer str, size_type pos, size_type count) const noexcept\n{\n  if (count == 0)\n    return pos;\n  if (pos >= size_)\n    pos = size_ - 1;\n  if (pos < count - 1)\n    return npos;\n  for (auto i = pos; i >= count - 1; --i)\n  {\n    if (*(buffer_ + i) == *(str + count - 1))\n    {\n      size_type j = 1;\n      for (; j < count; ++j)\n      {\n        if (*(buffer_ + i - j) != *(str + count - j - 1))\n          break;\n      }\n      if (j == count)\n        return i - count + 1;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始反向查找字符串 str，与 find 类似\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nrfind(const basic_string& str, size_type pos) const noexcept\n{\n  const size_type count = str.size_;\n  if (pos >= size_)\n    pos = size_ - 1;\n  if (count == 0)\n    return pos;\n  if (pos < count - 1)\n    return npos;\n  for (auto i = pos; i >= count - 1; --i)\n  {\n    if (*(buffer_ + i) == str[count - 1])\n    {\n      size_type j = 1;\n      for (; j < count; ++j)\n      {\n        if (*(buffer_ + i - j) != str[count - j - 1])\n          break;\n      }\n      if (j == count)\n        return i - count + 1;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找 ch 出现的第一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_of(value_type ch, size_type pos) const noexcept\n{\n  for (auto i = pos; i < size_; ++i)\n  {\n    if (*(buffer_ + i) == ch)\n      return i;\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找字符串 s 其中的一个字符出现的第一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_of(const_pointer s, size_type pos) const noexcept\n{\n  const size_type len = char_traits::length(s);\n  for (auto i = pos; i < size_; ++i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < len; ++j)\n    {\n      if (ch == *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找字符串 s \ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_of(const_pointer s, size_type pos, size_type count) const noexcept\n{\n  for (auto i = pos; i < size_; ++i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < count; ++j)\n    {\n      if (ch == *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找字符串 str 其中一个字符出现的第一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_of(const basic_string& str, size_type pos) const noexcept\n{\n  for (auto i = pos; i < size_; ++i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < str.size_; ++j)\n    {\n      if (ch == str[j])\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与 ch 不相等的第一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_not_of(value_type ch, size_type pos) const noexcept\n{\n  for (auto i = pos; i < size_; ++i)\n  {\n    if (*(buffer_ + i) != ch)\n      return i;\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 s 其中一个字符不相等的第一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_not_of(const_pointer s, size_type pos) const noexcept\n{\n  const size_type len = char_traits::length(s);\n  for (auto i = pos; i < size_; ++i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < len; ++j)\n    {\n      if (ch != *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的第一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_not_of(const_pointer s, size_type pos, size_type count) const noexcept\n{\n  for (auto i = pos; i < size_; ++i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < count; ++j)\n    {\n      if (ch != *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 str 的字符中不相等的第一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_first_not_of(const basic_string& str, size_type pos) const noexcept\n{\n  for (auto i = pos; i < size_; ++i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < str.size_; ++j)\n    {\n      if (ch != str[j])\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与 ch 相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_of(value_type ch, size_type pos) const noexcept\n{\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    if (*(buffer_ + i) == ch)\n      return i;\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 s 其中一个字符相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_of(const_pointer s, size_type pos) const noexcept\n{\n  const size_type len = char_traits::length(s);\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < len; ++j)\n    {\n      if (ch == *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 s 前 count 个字符中相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_of(const_pointer s, size_type pos, size_type count) const noexcept\n{\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < count; ++j)\n    {\n      if (ch == *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 str 字符中相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_of(const basic_string& str, size_type pos) const noexcept\n{\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < str.size_; ++j)\n    {\n      if (ch == str[j])\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与 ch 字符不相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_not_of(value_type ch, size_type pos) const noexcept\n{\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    if (*(buffer_ + i) != ch)\n      return i;\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 s 的字符中不相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_not_of(const_pointer s, size_type pos) const noexcept\n{\n  const size_type len = char_traits::length(s);\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < len; ++j)\n    {\n      if (ch != *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_not_of(const_pointer s, size_type pos, size_type count) const noexcept\n{\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < count; ++j)\n    {\n      if (ch != *(s + j))\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 从下标 pos 开始查找与字符串 str 字符中不相等的最后一个位置\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\nfind_last_not_of(const basic_string& str, size_type pos) const noexcept\n{\n  for (auto i = size_ - 1; i >= pos; --i)\n  {\n    value_type ch = *(buffer_ + i);\n    for (size_type j = 0; j < str.size_; ++j)\n    {\n      if (ch != str[j])\n        return i;\n    }\n  }\n  return npos;\n}\n\n// 返回从下标 pos 开始字符为 ch 的元素出现的次数\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::size_type\nbasic_string<CharType, CharTraits>::\ncount(value_type ch, size_type pos) const noexcept\n{\n  size_type n = 0;\n  for (auto i = pos; i < size_; ++i)\n  {\n    if (*(buffer_ + i) == ch)\n      ++n;\n  }\n  return n;\n}\n\n/*****************************************************************************************/\n// helper function\n\n// 尝试初始化一段 buffer，若分配失败则忽略，不会抛出异常\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\ntry_init() noexcept\n{\n  try\n  {\n    buffer_ = data_allocator::allocate(static_cast<size_type>(STRING_INIT_SIZE));\n    size_ = 0;\n    cap_ = 0;\n  }\n  catch (...)\n  {\n    buffer_ = nullptr;\n    size_ = 0;\n    cap_ = 0;\n    // no throw\n  }\n}\n\n// fill_init 函数\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nfill_init(size_type n, value_type ch)\n{\n  const auto init_size = mystl::max(static_cast<size_type>(STRING_INIT_SIZE), n + 1);\n  buffer_ = data_allocator::allocate(init_size);\n  char_traits::fill(buffer_, ch, n);\n  size_ = n;\n  cap_ = init_size;\n}\n\n// copy_init 函数\ntemplate <class CharType, class CharTraits>\ntemplate <class Iter>\nvoid basic_string<CharType, CharTraits>::\ncopy_init(Iter first, Iter last, mystl::input_iterator_tag)\n{\n  size_type n = mystl::distance(first, last);\n  const auto init_size = mystl::max(static_cast<size_type>(STRING_INIT_SIZE), n + 1);\n  try\n  {\n    buffer_ = data_allocator::allocate(init_size);\n    size_ = n;\n    cap_ = init_size;\n  }\n  catch (...)\n  {\n    buffer_ = nullptr;\n    size_ = 0;\n    cap_ = 0;\n    throw;\n  }\n  for (; n > 0; --n, ++first)\n    append(*first);\n}\n\ntemplate <class CharType, class CharTraits>\ntemplate <class Iter>\nvoid basic_string<CharType, CharTraits>::\ncopy_init(Iter first, Iter last, mystl::forward_iterator_tag)\n{\n  const size_type n = mystl::distance(first, last);\n  const auto init_size = mystl::max(static_cast<size_type>(STRING_INIT_SIZE), n + 1);\n  try\n  {\n    buffer_ = data_allocator::allocate(init_size);\n    size_ = n;\n    cap_ = init_size;\n    mystl::uninitialized_copy(first, last, buffer_);\n  }\n  catch (...)\n  {\n    buffer_ = nullptr;\n    size_ = 0;\n    cap_ = 0;\n    throw;\n  }\n}\n\n// init_from 函数\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\ninit_from(const_pointer src, size_type pos, size_type count)\n{\n  const auto init_size = mystl::max(static_cast<size_type>(STRING_INIT_SIZE), count + 1);\n  buffer_ = data_allocator::allocate(init_size);\n  char_traits::copy(buffer_, src + pos, count);\n  size_ = count;\n  cap_ = init_size;\n}\n\n// destroy_buffer 函数\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\ndestroy_buffer()\n{\n  if (buffer_ != nullptr)\n  {\n    data_allocator::deallocate(buffer_, cap_);\n    buffer_ = nullptr;\n    size_ = 0;\n    cap_ = 0;\n  }\n}\n\n// to_raw_pointer 函数\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::const_pointer\nbasic_string<CharType, CharTraits>::\nto_raw_pointer() const\n{\n  *(buffer_ + size_) = value_type();\n  return buffer_;\n}\n\n// reinsert 函数\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nreinsert(size_type size)\n{\n  auto new_buffer = data_allocator::allocate(size);\n  try\n  {\n    char_traits::move(new_buffer, buffer_, size);\n  }\n  catch (...)\n  {\n    data_allocator::deallocate(new_buffer);\n  }\n  buffer_ = new_buffer;\n  size_ = size;\n  cap_ = size;\n}\n\n// append_range，末尾追加一段 [first, last) 内的字符\ntemplate <class CharType, class CharTraits>\ntemplate <class Iter>\nbasic_string<CharType, CharTraits>&\nbasic_string<CharType, CharTraits>::\nappend_range(Iter first, Iter last)\n{\n  const size_type n = mystl::distance(first, last);\n  THROW_LENGTH_ERROR_IF(size_ > max_size() - n,\n                        \"basic_string<Char, Tratis>'s size too big\");\n  if (cap_ - size_ < n)\n  {\n    reallocate(n);\n  }\n  mystl::uninitialized_copy_n(first, n, buffer_ + size_);\n  size_ += n;\n  return *this;\n}\n\ntemplate <class CharType, class CharTraits>\nint basic_string<CharType, CharTraits>::\ncompare_cstr(const_pointer s1, size_type n1, const_pointer s2, size_type n2) const\n{\n  auto rlen = mystl::min(n1, n2);\n  auto res = char_traits::compare(s1, s2, rlen);\n  if (res != 0) return res;\n  if (n1 < n2) return -1;\n  if (n1 > n2) return 1;\n  return 0;\n}\n\n// 把 first 开始的 count1 个字符替换成 str 开始的 count2 个字符\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>& \nbasic_string<CharType, CharTraits>::\nreplace_cstr(const_iterator first, size_type count1, const_pointer str, size_type count2)\n{\n  if (static_cast<size_type>(cend() - first) < count1)\n  {\n    count1 = cend() - first;\n  }\n  if (count1 < count2)\n  {\n    const size_type add = count2 - count1;\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - add,\n                          \"basic_string<Char, Traits>'s size too big\");\n    if (size_ > cap_ - add)\n    {\n      reallocate(add);\n    }\n    pointer r = const_cast<pointer>(first);\n    char_traits::move(r + count2, first + count1, end() - (first + count1));\n    char_traits::copy(r, str, count2);\n    size_ += add;\n  }\n  else\n  {\n    pointer r = const_cast<pointer>(first);\n    char_traits::move(r + count2, first + count1, end() - (first + count1));\n    char_traits::copy(r, str, count2);\n    size_ -= (count1 - count2);\n  }\n  return *this;\n}\n\n// 把 first 开始的 count1 个字符替换成 count2 个 ch 字符\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>&\nbasic_string<CharType, CharTraits>::\nreplace_fill(const_iterator first, size_type count1, size_type count2, value_type ch)\n{\n  if (static_cast<size_type>(cend() - first) < count1)\n  {\n    count1 = cend() - first;\n  }\n  if (count1 < count2)\n  {\n    const size_type add = count2 - count1;\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - add,\n                          \"basic_string<Char, Traits>'s size too big\");\n    if (size_ > cap_ - add)\n    {\n      reallocate(add);\n    }\n    pointer r = const_cast<pointer>(first);\n    char_traits::move(r + count2, first + count1, end() - (first + count1));\n    char_traits::fill(r, ch, count2);\n    size_ += add;\n  }\n  else\n  {\n    pointer r = const_cast<pointer>(first);\n    char_traits::move(r + count2, first + count1, end() - (first + count1));\n    char_traits::fill(r, ch, count2);\n    size_ -= (count1 - count2);\n  }\n  return *this;\n}\n\n// 把 [first, last) 的字符替换成 [first2, last2)\ntemplate <class CharType, class CharTraits>\ntemplate <class Iter>\nbasic_string<CharType, CharTraits>&\nbasic_string<CharType, CharTraits>::\nreplace_copy(const_iterator first, const_iterator last, Iter first2, Iter last2)\n{\n  size_type len1 = last - first;\n  size_type len2 = last2 - first2;\n  if (len1 < len2)\n  {\n    const size_type add = len2 - len1;\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - add,\n                          \"basic_string<Char, Traits>'s size too big\");\n    if (size_ > cap_ - add)\n    {\n      reallocate(add);\n    }\n    pointer r = const_cast<pointer>(first);\n    char_traits::move(r + len2, first + len1, end() - (first + len1));\n    char_traits::copy(r, first2, len2);\n    size_ += add;\n  }\n  else\n  {\n    pointer r = const_cast<pointer>(first);\n    char_traits::move(r + len2, first + len1, end() - (first + len1));\n    char_traits::copy(r, first2, len2);\n    size_ -= (len1 - len2);\n  }\n  return *this;\n}\n\n// reallocate 函数\ntemplate <class CharType, class CharTraits>\nvoid basic_string<CharType, CharTraits>::\nreallocate(size_type need)\n{\n  const auto new_cap = mystl::max(cap_ + need, cap_ + (cap_ >> 1));\n  auto new_buffer = data_allocator::allocate(new_cap);\n  char_traits::move(new_buffer, buffer_, size_);\n  data_allocator::deallocate(buffer_);\n  buffer_ = new_buffer;\n  cap_ = new_cap;\n}\n\n// reallocate_and_fill 函数\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::iterator\nbasic_string<CharType, CharTraits>::\nreallocate_and_fill(iterator pos, size_type n, value_type ch)\n{\n  const auto r = pos - buffer_;\n  const auto old_cap = cap_;\n  const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1));\n  auto new_buffer = data_allocator::allocate(new_cap);\n  auto e1 = char_traits::move(new_buffer, buffer_, r) + r;\n  auto e2 = char_traits::fill(e1, ch, n) + n;\n  char_traits::move(e2, buffer_ + r, size_ - r);\n  data_allocator::deallocate(buffer_, old_cap);\n  buffer_ = new_buffer;\n  size_ += n;\n  cap_ = new_cap;\n  return buffer_ + r;\n}\n\n// reallocate_and_copy 函数\ntemplate <class CharType, class CharTraits>\ntypename basic_string<CharType, CharTraits>::iterator\nbasic_string<CharType, CharTraits>::\nreallocate_and_copy(iterator pos, const_iterator first, const_iterator last)\n{\n  const auto r = pos - buffer_;\n  const auto old_cap = cap_;\n  const size_type n = mystl::distance(first, last);\n  const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1));\n  auto new_buffer = data_allocator::allocate(new_cap);\n  auto e1 = char_traits::move(new_buffer, buffer_, r) + r;\n  auto e2 = mystl::uninitialized_copy_n(first, n, e1) + n;\n  char_traits::move(e2, buffer_ + r, size_ - r);\n  data_allocator::deallocate(buffer_, old_cap);\n  buffer_ = new_buffer;\n  size_ += n;\n  cap_ = new_cap;\n  return buffer_ + r;\n}\n\n/*****************************************************************************************/\n// 重载全局操作符\n\n// 重载 operator+\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(const basic_string<CharType, CharTraits>& lhs, \n          const basic_string<CharType, CharTraits>& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(lhs);\n  tmp.append(rhs);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(const CharType* lhs, const basic_string<CharType, CharTraits>& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(lhs);\n  tmp.append(rhs);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(CharType ch, const basic_string<CharType, CharTraits>& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(1, ch);\n  tmp.append(rhs);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(const basic_string<CharType, CharTraits>& lhs, const CharType* rhs)\n{\n  basic_string<CharType, CharTraits> tmp(lhs);\n  tmp.append(rhs);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(const basic_string<CharType, CharTraits>& lhs, CharType ch)\n{\n  basic_string<CharType, CharTraits> tmp(lhs);\n  tmp.append(1, ch);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(basic_string<CharType, CharTraits>&& lhs,\n          const basic_string<CharType, CharTraits>& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(mystl::move(lhs));\n  tmp.append(rhs);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(const basic_string<CharType, CharTraits>& lhs,\n          basic_string<CharType, CharTraits>&& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(mystl::move(rhs));\n  tmp.insert(tmp.begin(), lhs.begin(), lhs.end());\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(basic_string<CharType, CharTraits>&& lhs,\n          basic_string<CharType, CharTraits>&& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(mystl::move(lhs));\n  tmp.append(rhs);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(const CharType* lhs, basic_string<CharType, CharTraits>&& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(mystl::move(rhs));\n  tmp.insert(tmp.begin(), lhs, lhs + char_traits<CharType>::length(lhs));\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(CharType ch, basic_string<CharType, CharTraits>&& rhs)\n{\n  basic_string<CharType, CharTraits> tmp(mystl::move(rhs));\n  tmp.insert(tmp.begin(), ch);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(basic_string<CharType, CharTraits>&& lhs, const CharType* rhs)\n{\n  basic_string<CharType, CharTraits> tmp(mystl::move(lhs));\n  tmp.append(rhs);\n  return tmp;\n}\n\ntemplate <class CharType, class CharTraits>\nbasic_string<CharType, CharTraits>\noperator+(basic_string<CharType, CharTraits>&& lhs, CharType ch)\n{\n  basic_string<CharType, CharTraits> tmp(mystl::move(lhs));\n  tmp.append(1, ch);\n  return tmp;\n}\n\n// 重载比较操作符\ntemplate <class CharType, class CharTraits>\nbool operator==(const basic_string<CharType, CharTraits>& lhs,\n                const basic_string<CharType, CharTraits>& rhs)\n{\n  return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;\n}\n\ntemplate <class CharType, class CharTraits>\nbool operator!=(const basic_string<CharType, CharTraits>& lhs,\n                const basic_string<CharType, CharTraits>& rhs)\n{\n  return lhs.size() != rhs.size() || lhs.compare(rhs) != 0;\n}\n\ntemplate <class CharType, class CharTraits>\nbool operator<(const basic_string<CharType, CharTraits>& lhs,\n               const basic_string<CharType, CharTraits>& rhs)\n{\n  return lhs.compare(rhs) < 0;\n}\n\ntemplate <class CharType, class CharTraits>\nbool operator<=(const basic_string<CharType, CharTraits>& lhs,\n                const basic_string<CharType, CharTraits>& rhs)\n{\n  return lhs.compare(rhs) <= 0;\n}\n\ntemplate <class CharType, class CharTraits>\nbool operator>(const basic_string<CharType, CharTraits>& lhs,\n               const basic_string<CharType, CharTraits>& rhs)\n{\n  return lhs.compare(rhs) > 0;\n}\n\ntemplate <class CharType, class CharTraits>\nbool operator>=(const basic_string<CharType, CharTraits>& lhs,\n                const basic_string<CharType, CharTraits>& rhs)\n{\n  return lhs.compare(rhs) >= 0;\n}\n\n// 重载 mystl 的 swap\ntemplate <class CharType, class CharTraits>\nvoid swap(basic_string<CharType, CharTraits>& lhs,\n          basic_string<CharType, CharTraits>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n// 特化 mystl::hash\ntemplate <class CharType, class CharTraits>\nstruct hash<basic_string<CharType, CharTraits>>\n{\n  size_t operator()(const basic_string<CharType, CharTraits>& str)\n  {\n    return bitwise_hash((const unsigned char*)str.c_str(),\n                        str.size() * sizeof(CharType));\n  }\n};\n\n} // namespace mystl\n#endif // !MYTINYSTL_BASIC_STRING_H_\n\n"
  },
  {
    "path": "MyTinySTL/construct.h",
    "content": "﻿#ifndef MYTINYSTL_CONSTRUCT_H_\n#define MYTINYSTL_CONSTRUCT_H_\n\n// 这个头文件包含两个函数 construct，destroy\n// construct : 负责对象的构造\n// destroy   : 负责对象的析构\n\n#include <new>\n\n#include \"type_traits.h\"\n#include \"iterator.h\"\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4100)  // unused parameter\n#endif // _MSC_VER\n\nnamespace mystl\n{\n\n// construct 构造对象\n\ntemplate <class Ty>\nvoid construct(Ty* ptr)\n{\n  ::new ((void*)ptr) Ty();\n}\n\ntemplate <class Ty1, class Ty2>\nvoid construct(Ty1* ptr, const Ty2& value)\n{\n  ::new ((void*)ptr) Ty1(value);\n}\n\ntemplate <class Ty, class... Args>\nvoid construct(Ty* ptr, Args&&... args)\n{\n  ::new ((void*)ptr) Ty(mystl::forward<Args>(args)...);\n}\n\n// destroy 将对象析构\n\ntemplate <class Ty>\nvoid destroy_one(Ty*, std::true_type) {}\n\ntemplate <class Ty>\nvoid destroy_one(Ty* pointer, std::false_type)\n{\n  if (pointer != nullptr)\n  {\n    pointer->~Ty();\n  }\n}\n\ntemplate <class ForwardIter>\nvoid destroy_cat(ForwardIter , ForwardIter , std::true_type) {}\n\ntemplate <class ForwardIter>\nvoid destroy_cat(ForwardIter first, ForwardIter last, std::false_type)\n{\n  for (; first != last; ++first)\n    destroy(&*first);\n}\n\ntemplate <class Ty>\nvoid destroy(Ty* pointer)\n{\n  destroy_one(pointer, std::is_trivially_destructible<Ty>{});\n}\n\ntemplate <class ForwardIter>\nvoid destroy(ForwardIter first, ForwardIter last)\n{\n  destroy_cat(first, last, std::is_trivially_destructible<\n              typename iterator_traits<ForwardIter>::value_type>{});\n}\n\n} // namespace mystl\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif // _MSC_VER\n\n#endif // !MYTINYSTL_CONSTRUCT_H_\n\n"
  },
  {
    "path": "MyTinySTL/deque.h",
    "content": "﻿#ifndef MYTINYSTL_DEQUE_H_\n#define MYTINYSTL_DEQUE_H_\n\n// 这个头文件包含了一个模板类 deque\n// deque: 双端队列\n\n// notes:\n//\n// 异常保证：\n// mystl::deque<T> 满足基本异常保证，部分函数无异常保证，并对以下等函数做强异常安全保证：\n//   * emplace_front\n//   * emplace_back\n//   * emplace\n//   * push_front\n//   * push_back\n//   * insert\n\n#include <initializer_list>\n\n#include \"iterator.h\"\n#include \"memory.h\"\n#include \"util.h\"\n#include \"exceptdef.h\"\n\nnamespace mystl\n{\n\n#ifdef max\n#pragma message(\"#undefing marco max\")\n#undef max\n#endif // max\n\n#ifdef min\n#pragma message(\"#undefing marco min\")\n#undef min\n#endif // min\n\n// deque map 初始化的大小\n#ifndef DEQUE_MAP_INIT_SIZE\n#define DEQUE_MAP_INIT_SIZE 8\n#endif\n\ntemplate <class T>\nstruct deque_buf_size\n{\n  static constexpr size_t value = sizeof(T) < 256 ? 4096 / sizeof(T) : 16;\n};\n\n// deque 的迭代器设计\ntemplate <class T, class Ref, class Ptr>\nstruct deque_iterator : public iterator<random_access_iterator_tag, T>\n{\n  typedef deque_iterator<T, T&, T*>             iterator;\n  typedef deque_iterator<T, const T&, const T*> const_iterator;\n  typedef deque_iterator                        self;\n\n  typedef T            value_type;\n  typedef Ptr          pointer;\n  typedef Ref          reference;\n  typedef size_t       size_type;\n  typedef ptrdiff_t    difference_type;\n  typedef T*           value_pointer;\n  typedef T**          map_pointer;\n\n  static const size_type buffer_size = deque_buf_size<T>::value;\n\n  // 迭代器所含成员数据\n  value_pointer cur;    // 指向所在缓冲区的当前元素\n  value_pointer first;  // 指向所在缓冲区的头部\n  value_pointer last;   // 指向所在缓冲区的尾部\n  map_pointer   node;   // 缓冲区所在节点\n\n  // 构造、复制、移动函数\n  deque_iterator() noexcept\n    :cur(nullptr), first(nullptr), last(nullptr), node(nullptr) {}\n\n  deque_iterator(value_pointer v, map_pointer n)\n    :cur(v), first(*n), last(*n + buffer_size), node(n) {}\n\n  deque_iterator(const iterator& rhs)\n    :cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node)\n  {\n  }\n  deque_iterator(iterator&& rhs) noexcept\n    :cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node)\n  {\n    rhs.cur = nullptr;\n    rhs.first = nullptr;\n    rhs.last = nullptr;\n    rhs.node = nullptr;\n  }\n\n  deque_iterator(const const_iterator& rhs)\n    :cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node)\n  {\n  }\n\n  self& operator=(const iterator& rhs)\n  {\n    if (this != &rhs)\n    {\n      cur = rhs.cur;\n      first = rhs.first;\n      last = rhs.last;\n      node = rhs.node;\n    }\n    return *this;\n  }\n\n  // 转到另一个缓冲区\n  void set_node(map_pointer new_node)\n  {\n    node = new_node;\n    first = *new_node;\n    last = first + buffer_size;\n  }\n\n  // 重载运算符\n  reference operator*()  const { return *cur; }\n  pointer   operator->() const { return cur; }\n\n  difference_type operator-(const self& x) const\n  {\n    return static_cast<difference_type>(buffer_size) * (node - x.node)\n      + (cur - first) - (x.cur - x.first);\n  }\n\n  self& operator++()\n  {\n    ++cur;\n    if (cur == last)\n    { // 如果到达缓冲区的尾\n      set_node(node + 1);\n      cur = first;\n    }\n    return *this;\n  }\n  self operator++(int)\n  {\n    self tmp = *this;\n    ++*this;\n    return tmp;\n  }\n\n  self& operator--()\n  {\n    if (cur == first)\n    { // 如果到达缓冲区的头\n      set_node(node - 1);\n      cur = last;\n    }\n    --cur;\n    return *this;\n  }\n  self operator--(int)\n  {\n    self tmp = *this;\n    --*this;\n    return tmp;\n  }\n\n  self& operator+=(difference_type n)\n  {\n    const auto offset = n + (cur - first);\n    if (offset >= 0 && offset < static_cast<difference_type>(buffer_size))\n    { // 仍在当前缓冲区\n      cur += n;\n    }\n    else\n    { // 要跳到其他的缓冲区\n      const auto node_offset = offset > 0\n        ? offset / static_cast<difference_type>(buffer_size)\n        : -static_cast<difference_type>((-offset - 1) / buffer_size) - 1;\n      set_node(node + node_offset);\n      cur = first + (offset - node_offset * static_cast<difference_type>(buffer_size));\n    }\n    return *this;\n  }\n  self operator+(difference_type n) const\n  {\n    self tmp = *this;\n    return tmp += n;\n  }\n  self& operator-=(difference_type n)\n  {\n    return *this += -n;\n  }\n  self operator-(difference_type n) const\n  {\n    self tmp = *this;\n    return tmp -= n;\n  }\n\n  reference operator[](difference_type n) const { return *(*this + n); }\n\n  // 重载比较操作符\n  bool operator==(const self& rhs) const { return cur == rhs.cur; }\n  bool operator< (const self& rhs) const\n  { return node == rhs.node ? (cur < rhs.cur) : (node < rhs.node); }\n  bool operator!=(const self& rhs) const { return !(*this == rhs); }\n  bool operator> (const self& rhs) const { return rhs < *this; }\n  bool operator<=(const self& rhs) const { return !(rhs < *this); }\n  bool operator>=(const self& rhs) const { return !(*this < rhs); }\n};\n\n// 模板类 deque\n// 模板参数代表数据类型\ntemplate <class T>\nclass deque\n{\npublic:\n  // deque 的型别定义\n  typedef mystl::allocator<T>                      allocator_type;\n  typedef mystl::allocator<T>                      data_allocator;\n  typedef mystl::allocator<T*>                     map_allocator;\n\n  typedef typename allocator_type::value_type      value_type;\n  typedef typename allocator_type::pointer         pointer;\n  typedef typename allocator_type::const_pointer   const_pointer;\n  typedef typename allocator_type::reference       reference;\n  typedef typename allocator_type::const_reference const_reference;\n  typedef typename allocator_type::size_type       size_type;\n  typedef typename allocator_type::difference_type difference_type;\n  typedef pointer*                                 map_pointer;\n  typedef const_pointer*                           const_map_pointer;\n\n  typedef deque_iterator<T, T&, T*>                iterator;\n  typedef deque_iterator<T, const T&, const T*>    const_iterator;\n  typedef mystl::reverse_iterator<iterator>        reverse_iterator;\n  typedef mystl::reverse_iterator<const_iterator>  const_reverse_iterator;\n\n  allocator_type get_allocator() { return allocator_type(); }\n\n  static const size_type buffer_size = deque_buf_size<T>::value;\n\nprivate:\n  // 用以下四个数据来表现一个 deque\n  iterator       begin_;     // 指向第一个节点\n  iterator       end_;       // 指向最后一个结点\n  map_pointer    map_;       // 指向一块 map，map 中的每个元素都是一个指针，指向一个缓冲区\n  size_type      map_size_;  // map 内指针的数目\n\npublic:\n  // 构造、复制、移动、析构函数\n\n  deque()\n  { fill_init(0, value_type()); }\n\n  explicit deque(size_type n)\n  { fill_init(n, value_type()); }\n\n  deque(size_type n, const value_type& value)\n  { fill_init(n, value); }\n\n  template <class IIter, typename std::enable_if<\n    mystl::is_input_iterator<IIter>::value, int>::type = 0>\n  deque(IIter first, IIter last)\n  { copy_init(first, last, iterator_category(first)); }\n\n  deque(std::initializer_list<value_type> ilist)\n  {\n    copy_init(ilist.begin(), ilist.end(), mystl::forward_iterator_tag());\n  }\n\n  deque(const deque& rhs)\n  {\n    copy_init(rhs.begin(), rhs.end(), mystl::forward_iterator_tag());\n  }\n  deque(deque&& rhs) noexcept\n    :begin_(mystl::move(rhs.begin_)),\n    end_(mystl::move(rhs.end_)),\n    map_(rhs.map_),\n    map_size_(rhs.map_size_)\n  {\n    rhs.map_ = nullptr;\n    rhs.map_size_ = 0;\n  }\n\n  deque& operator=(const deque& rhs);\n  deque& operator=(deque&& rhs);\n\n  deque& operator=(std::initializer_list<value_type> ilist)\n  {\n    deque tmp(ilist);\n    swap(tmp);\n    return *this;\n  }\n\n  ~deque()\n  {\n    if (map_ != nullptr)\n    {\n      clear();\n      data_allocator::deallocate(*begin_.node, buffer_size);\n      *begin_.node = nullptr;\n      map_allocator::deallocate(map_, map_size_);\n      map_ = nullptr;\n    }\n  }\n\npublic:\n  // 迭代器相关操作\n\n  iterator               begin()         noexcept\n  { return begin_; }\n  const_iterator         begin()   const noexcept\n  { return begin_; }\n  iterator               end()           noexcept\n  { return end_; }\n  const_iterator         end()     const noexcept\n  { return end_; }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关操作\n\n  bool      empty()    const noexcept  { return begin() == end(); }\n  size_type size()     const noexcept  { return end_ - begin_; }\n  size_type max_size() const noexcept  { return static_cast<size_type>(-1); }\n  void      resize(size_type new_size) { resize(new_size, value_type()); }\n  void      resize(size_type new_size, const value_type& value);\n  void      shrink_to_fit() noexcept;\n\n  // 访问元素相关操作 \n  reference       operator[](size_type n)\n  {\n    MYSTL_DEBUG(n < size());\n    return begin_[n];\n  }\n  const_reference operator[](size_type n) const\n  {\n    MYSTL_DEBUG(n < size());\n    return begin_[n];\n  }\n\n  reference       at(size_type n)      \n  { \n    THROW_OUT_OF_RANGE_IF(!(n < size()), \"deque<T>::at() subscript out of range\");\n    return (*this)[n];\n  }\n  const_reference at(size_type n) const\n  {\n    THROW_OUT_OF_RANGE_IF(!(n < size()), \"deque<T>::at() subscript out of range\");\n    return (*this)[n]; \n  }\n\n  reference       front()\n  {\n    MYSTL_DEBUG(!empty());\n    return *begin();\n  }\n  const_reference front() const\n  {\n    MYSTL_DEBUG(!empty());\n    return *begin();\n  }\n  reference       back()\n  {\n    MYSTL_DEBUG(!empty());\n    return *(end() - 1);\n  }\n  const_reference back() const\n  {\n    MYSTL_DEBUG(!empty());\n    return *(end() - 1);\n  }\n\n  // 修改容器相关操作\n\n  // assign\n\n  void     assign(size_type n, const value_type& value)\n  { fill_assign(n, value); }\n\n  template <class IIter, typename std::enable_if<\n    mystl::is_input_iterator<IIter>::value, int>::type = 0>\n  void     assign(IIter first, IIter last)\n  { copy_assign(first, last, iterator_category(first)); }\n\n  void     assign(std::initializer_list<value_type> ilist)\n  { copy_assign(ilist.begin(), ilist.end(), mystl::forward_iterator_tag{}); }\n\n  // emplace_front / emplace_back / emplace\n\n  template <class ...Args>\n  void     emplace_front(Args&& ...args);\n  template <class ...Args>\n  void     emplace_back(Args&& ...args);\n  template <class ...Args>\n  iterator emplace(iterator pos, Args&& ...args);\n\n  // push_front / push_back\n\n  void     push_front(const value_type& value);\n  void     push_back(const value_type& value);\n\n  void     push_front(value_type&& value) { emplace_front(mystl::move(value)); }\n  void     push_back(value_type&& value)  { emplace_back(mystl::move(value)); }\n\n  // pop_back / pop_front\n\n  void     pop_front();\n  void     pop_back();\n\n  // insert\n\n  iterator insert(iterator position, const value_type& value);\n  iterator insert(iterator position, value_type&& value);\n  void     insert(iterator position, size_type n, const value_type& value);\n  template <class IIter, typename std::enable_if<\n    mystl::is_input_iterator<IIter>::value, int>::type = 0>\n  void     insert(iterator position, IIter first, IIter last)\n  { insert_dispatch(position, first, last, iterator_category(first)); }\n\n  // erase /clear\n\n  iterator erase(iterator position);\n  iterator erase(iterator first, iterator last);\n  void     clear();\n\n  // swap\n\n  void     swap(deque& rhs) noexcept;\n\nprivate:\n  // helper functions\n\n  // create node / destroy node\n  map_pointer create_map(size_type size);\n  void        create_buffer(map_pointer nstart, map_pointer nfinish);\n  void        destroy_buffer(map_pointer nstart, map_pointer nfinish);\n\n  // initialize\n  void        map_init(size_type nelem);\n  void        fill_init(size_type n, const value_type& value);\n  template <class IIter>\n  void        copy_init(IIter, IIter, input_iterator_tag);\n  template <class FIter>\n  void        copy_init(FIter, FIter, forward_iterator_tag);\n\n  // assign\n  void        fill_assign(size_type n, const value_type& value);\n  template <class IIter>\n  void        copy_assign(IIter first, IIter last, input_iterator_tag);\n  template <class FIter>\n  void        copy_assign(FIter first, FIter last, forward_iterator_tag);\n\n  // insert\n  template <class... Args>\n  iterator    insert_aux(iterator position, Args&& ...args);\n  void        fill_insert(iterator position, size_type n, const value_type& x);\n  template <class FIter>\n  void        copy_insert(iterator, FIter, FIter, size_type);\n  template <class IIter>\n  void        insert_dispatch(iterator, IIter, IIter, input_iterator_tag);\n  template <class FIter>\n  void        insert_dispatch(iterator, FIter, FIter, forward_iterator_tag);\n\n  // reallocate\n  void        require_capacity(size_type n, bool front);\n  void        reallocate_map_at_front(size_type need);\n  void        reallocate_map_at_back(size_type need);\n\n};\n\n/*****************************************************************************************/\n\n// 复制赋值运算符\ntemplate <class T>\ndeque<T>& deque<T>::operator=(const deque& rhs)\n{\n  if (this != &rhs)\n  {\n    const auto len = size();\n    if (len >= rhs.size())\n    {\n      erase(mystl::copy(rhs.begin_, rhs.end_, begin_), end_);\n    }\n    else\n    {\n      iterator mid = rhs.begin() + static_cast<difference_type>(len);\n      mystl::copy(rhs.begin_, mid, begin_);\n      insert(end_, mid, rhs.end_);\n    }\n  }\n  return *this;\n}\n\n// 移动赋值运算符\ntemplate <class T>\ndeque<T>& deque<T>::operator=(deque&& rhs)\n{\n  clear();\n  begin_ = mystl::move(rhs.begin_);\n  end_ = mystl::move(rhs.end_);\n  map_ = rhs.map_;\n  map_size_ = rhs.map_size_;\n  rhs.map_ = nullptr;\n  rhs.map_size_ = 0;\n  return *this;\n}\n\n// 重置容器大小\ntemplate <class T>\nvoid deque<T>::resize(size_type new_size, const value_type& value)\n{\n  const auto len = size();\n  if (new_size < len)\n  {\n    erase(begin_ + new_size, end_);\n  }\n  else\n  {\n    insert(end_, new_size - len, value);\n  }\n}\n\n// 减小容器容量\ntemplate <class T>\nvoid deque<T>::shrink_to_fit() noexcept\n{\n  // 至少会留下头部缓冲区\n  for (auto cur = map_; cur < begin_.node; ++cur)\n  {\n    data_allocator::deallocate(*cur, buffer_size);\n    *cur = nullptr;\n  }\n  for (auto cur = end_.node + 1; cur < map_ + map_size_; ++cur)\n  {\n    data_allocator::deallocate(*cur, buffer_size);\n    *cur = nullptr;\n  }\n}\n\n// 在头部就地构建元素\ntemplate <class T>\ntemplate <class ...Args>\nvoid deque<T>::emplace_front(Args&& ...args)\n{\n  if (begin_.cur != begin_.first)\n  {\n    data_allocator::construct(begin_.cur - 1, mystl::forward<Args>(args)...);\n    --begin_.cur;\n  }\n  else\n  {\n    require_capacity(1, true);\n    try\n    {\n      --begin_;\n      data_allocator::construct(begin_.cur, mystl::forward<Args>(args)...);\n    }\n    catch (...)\n    {\n      ++begin_;\n      throw;\n    }\n  }\n}\n\n// 在尾部就地构建元素\ntemplate <class T>\ntemplate <class ...Args>\nvoid deque<T>::emplace_back(Args&& ...args)\n{\n  if (end_.cur != end_.last - 1)\n  {\n    data_allocator::construct(end_.cur, mystl::forward<Args>(args)...);\n    ++end_.cur;\n  }\n  else\n  {\n    require_capacity(1, false);\n    data_allocator::construct(end_.cur, mystl::forward<Args>(args)...);\n    ++end_;\n  }\n}\n\n// 在 pos 位置就地构建元素\ntemplate <class T>\ntemplate <class ...Args>\ntypename deque<T>::iterator deque<T>::emplace(iterator pos, Args&& ...args)\n{\n  if (pos.cur == begin_.cur)\n  {\n    emplace_front(mystl::forward<Args>(args)...);\n    return begin_;\n  }\n  else if (pos.cur == end_.cur)\n  {\n    emplace_back(mystl::forward<Args>(args)...);\n    return end_ - 1;\n  }\n  return insert_aux(pos, mystl::forward<Args>(args)...);\n}\n\n// 在头部插入元素\ntemplate <class T>\nvoid deque<T>::push_front(const value_type& value)\n{\n  if (begin_.cur != begin_.first)\n  {\n    data_allocator::construct(begin_.cur - 1, value);\n    --begin_.cur;\n  }\n  else\n  {\n    require_capacity(1, true);\n    try\n    {\n      --begin_;\n      data_allocator::construct(begin_.cur, value);\n    }\n    catch (...)\n    {\n      ++begin_;\n      throw;\n    }\n  }\n}\n\n// 在尾部插入元素\ntemplate <class T>\nvoid deque<T>::push_back(const value_type& value)\n{\n  if (end_.cur != end_.last - 1)\n  {\n    data_allocator::construct(end_.cur, value);\n    ++end_.cur;\n  }\n  else\n  {\n    require_capacity(1, false);\n    data_allocator::construct(end_.cur, value);\n    ++end_;\n  }\n}\n\n// 弹出头部元素\ntemplate <class T>\nvoid deque<T>::pop_front()\n{\n  MYSTL_DEBUG(!empty());\n  if (begin_.cur != begin_.last - 1)\n  {\n    data_allocator::destroy(begin_.cur);\n    ++begin_.cur;\n  }\n  else\n  {\n    data_allocator::destroy(begin_.cur);\n    ++begin_;\n    destroy_buffer(begin_.node - 1, begin_.node - 1);\n  }\n}\n\n// 弹出尾部元素\ntemplate <class T>\nvoid deque<T>::pop_back()\n{\n  MYSTL_DEBUG(!empty());\n  if (end_.cur != end_.first)\n  {\n    --end_.cur;\n    data_allocator::destroy(end_.cur);\n  }\n  else\n  {\n    --end_;\n    data_allocator::destroy(end_.cur);\n    destroy_buffer(end_.node + 1, end_.node + 1);\n  }\n}\n\n// 在 position 处插入元素\ntemplate <class T>\ntypename deque<T>::iterator\ndeque<T>::insert(iterator position, const value_type& value)\n{\n  if (position.cur == begin_.cur)\n  {\n    push_front(value);\n    return begin_;\n  }\n  else if (position.cur == end_.cur)\n  {\n    push_back(value);\n    auto tmp = end_;\n    --tmp;\n    return tmp;\n  }\n  else\n  {\n    return insert_aux(position, value);\n  }\n}\n\ntemplate <class T>\ntypename deque<T>::iterator\ndeque<T>::insert(iterator position, value_type&& value)\n{\n  if (position.cur == begin_.cur)\n  {\n    emplace_front(mystl::move(value));\n    return begin_;\n  }\n  else if (position.cur == end_.cur)\n  {\n    emplace_back(mystl::move(value));\n    auto tmp = end_;\n    --tmp;\n    return tmp;\n  }\n  else\n  {\n    return insert_aux(position, mystl::move(value));\n  }\n}\n\n// 在 position 位置插入 n 个元素\ntemplate <class T>\nvoid deque<T>::insert(iterator position, size_type n, const value_type& value)\n{\n  if (position.cur == begin_.cur)\n  {\n    require_capacity(n, true);\n    auto new_begin = begin_ - n;\n    mystl::uninitialized_fill_n(new_begin, n, value);\n    begin_ = new_begin;\n  }\n  else if (position.cur == end_.cur)\n  {\n    require_capacity(n, false);\n    auto new_end = end_ + n;\n    mystl::uninitialized_fill_n(end_, n, value);\n    end_ = new_end;\n  }\n  else\n  {\n    fill_insert(position, n, value);\n  }\n}\n\n// 删除 position 处的元素\ntemplate <class T>\ntypename deque<T>::iterator\ndeque<T>::erase(iterator position)\n{\n  auto next = position;\n  ++next;\n  const size_type elems_before = position - begin_;\n  if (elems_before < (size() / 2))\n  {\n    mystl::copy_backward(begin_, position, next);\n    pop_front();\n  }\n  else\n  {\n    mystl::copy(next, end_, position);\n    pop_back();\n  }\n  return begin_ + elems_before;\n}\n\n// 删除[first, last)上的元素\ntemplate <class T>\ntypename deque<T>::iterator\ndeque<T>::erase(iterator first, iterator last)\n{\n  if (first == begin_ && last == end_)\n  {\n    clear();\n    return end_;\n  }\n  else\n  {\n    const size_type len = last - first;\n    const size_type elems_before = first - begin_;\n    if (elems_before < ((size() - len) / 2))\n    {\n      mystl::copy_backward(begin_, first, last);\n      auto new_begin = begin_ + len;\n      data_allocator::destroy(begin_.cur, new_begin.cur);\n      begin_ = new_begin;\n    }\n    else\n    {\n      mystl::copy(last, end_, first);\n      auto new_end = end_ - len;\n      data_allocator::destroy(new_end.cur, end_.cur);\n      end_ = new_end;\n    }\n    return begin_ + elems_before;\n  }\n}\n\n// 清空 deque\ntemplate <class T>\nvoid deque<T>::clear()\n{\n  // clear 会保留头部的缓冲区\n  for (map_pointer cur = begin_.node + 1; cur < end_.node; ++cur)\n  {\n    data_allocator::destroy(*cur, *cur + buffer_size);\n  }\n  if (begin_.node != end_.node)\n  { // 有两个以上的缓冲区\n    mystl::destroy(begin_.cur, begin_.last);\n    mystl::destroy(end_.first, end_.cur);\n  }\n  else\n  {\n    mystl::destroy(begin_.cur, end_.cur);\n  }\n  shrink_to_fit();\n  end_ = begin_;\n}\n\n// 交换两个 deque\ntemplate <class T>\nvoid deque<T>::swap(deque& rhs) noexcept\n{\n  if (this != &rhs)\n  {\n    mystl::swap(begin_, rhs.begin_);\n    mystl::swap(end_, rhs.end_);\n    mystl::swap(map_, rhs.map_);\n    mystl::swap(map_size_, rhs.map_size_);\n  }\n}\n\n/*****************************************************************************************/\n// helper function\n\ntemplate <class T>\ntypename deque<T>::map_pointer\ndeque<T>::create_map(size_type size)\n{\n  map_pointer mp = nullptr;\n  mp = map_allocator::allocate(size);\n  for (size_type i = 0; i < size; ++i)\n    *(mp + i) = nullptr;\n  return mp;\n}\n\n// create_buffer 函数\ntemplate <class T>\nvoid deque<T>::\ncreate_buffer(map_pointer nstart, map_pointer nfinish)\n{\n  map_pointer cur;\n  try\n  {\n    for (cur = nstart; cur <= nfinish; ++cur)\n    {\n      *cur = data_allocator::allocate(buffer_size);\n    }\n  }\n  catch (...)\n  {\n    while (cur != nstart)\n    {\n      --cur;\n      data_allocator::deallocate(*cur, buffer_size);\n      *cur = nullptr;\n    }\n    throw;\n  }\n}\n\n// destroy_buffer 函数\ntemplate <class T>\nvoid deque<T>::\ndestroy_buffer(map_pointer nstart, map_pointer nfinish)\n{\n  for (map_pointer n = nstart; n <= nfinish; ++n)\n  {\n    data_allocator::deallocate(*n, buffer_size);\n    *n = nullptr;\n  }\n}\n\n// map_init 函数\ntemplate <class T>\nvoid deque<T>::\nmap_init(size_type nElem)\n{\n  const size_type nNode = nElem / buffer_size + 1;  // 需要分配的缓冲区个数\n  map_size_ = mystl::max(static_cast<size_type>(DEQUE_MAP_INIT_SIZE), nNode + 2);\n  try\n  {\n    map_ = create_map(map_size_);\n  }\n  catch (...)\n  {\n    map_ = nullptr;\n    map_size_ = 0;\n    throw;\n  }\n\n  // 让 nstart 和 nfinish 都指向 map_ 最中央的区域，方便向头尾扩充\n  map_pointer nstart = map_ + (map_size_ - nNode) / 2;\n  map_pointer nfinish = nstart + nNode - 1;\n  try\n  {\n    create_buffer(nstart, nfinish);\n  }\n  catch (...)\n  {\n    map_allocator::deallocate(map_, map_size_);\n    map_ = nullptr;\n    map_size_ = 0;\n    throw;\n  }\n  begin_.set_node(nstart);\n  end_.set_node(nfinish);\n  begin_.cur = begin_.first;\n  end_.cur = end_.first + (nElem % buffer_size);\n}\n\n// fill_init 函数\ntemplate <class T>\nvoid deque<T>::\nfill_init(size_type n, const value_type& value)\n{\n  map_init(n);\n  if (n != 0)\n  {\n    for (auto cur = begin_.node; cur < end_.node; ++cur)\n    {\n      mystl::uninitialized_fill(*cur, *cur + buffer_size, value);\n    }\n    mystl::uninitialized_fill(end_.first, end_.cur, value);\n  }\n}\n\n// copy_init 函数\ntemplate <class T>\ntemplate <class IIter>\nvoid deque<T>::\ncopy_init(IIter first, IIter last, input_iterator_tag)\n{\n  const size_type n = mystl::distance(first, last);\n  map_init(n);\n  for (; first != last; ++first)\n    emplace_back(*first);\n}\n\ntemplate <class T>\ntemplate <class FIter>\nvoid deque<T>::\ncopy_init(FIter first, FIter last, forward_iterator_tag)\n{\n  const size_type n = mystl::distance(first, last);\n  map_init(n);\n  for (auto cur = begin_.node; cur < end_.node; ++cur)\n  {\n    auto next = first;\n    mystl::advance(next, buffer_size);\n    mystl::uninitialized_copy(first, next, *cur);\n    first = next;\n  }\n  mystl::uninitialized_copy(first, last, end_.first);\n}\n\n// fill_assign 函数\ntemplate <class T>\nvoid deque<T>::\nfill_assign(size_type n, const value_type& value)\n{\n  if (n > size())\n  {\n    mystl::fill(begin(), end(), value);\n    insert(end(), n - size(), value);\n  }\n  else\n  {\n    erase(begin() + n, end());\n    mystl::fill(begin(), end(), value);\n  }\n}\n\n// copy_assign 函数\ntemplate <class T>\ntemplate <class IIter>\nvoid deque<T>::\ncopy_assign(IIter first, IIter last, input_iterator_tag)\n{\n  auto first1 = begin();\n  auto last1 = end();\n  for (; first != last && first1 != last1; ++first, ++first1)\n  {\n    *first1 = *first;\n  }\n  if (first1 != last1)\n  {\n    erase(first1, last1);\n  }\n  else\n  {\n    insert_dispatch(end_, first, last, input_iterator_tag{});\n  }\n}\n\ntemplate <class T>\ntemplate <class FIter>\nvoid deque<T>::\ncopy_assign(FIter first, FIter last, forward_iterator_tag)\n{  \n  const size_type len1 = size();\n  const size_type len2 = mystl::distance(first, last);\n  if (len1 < len2)\n  {\n    auto next = first;\n    mystl::advance(next, len1);\n    mystl::copy(first, next, begin_);\n    insert_dispatch(end_, next, last, forward_iterator_tag{});\n  }\n  else\n  {\n    erase(mystl::copy(first, last, begin_), end_);\n  }\n}\n\n// insert_aux 函数\ntemplate <class T>\ntemplate <class... Args>\ntypename deque<T>::iterator\ndeque<T>::\ninsert_aux(iterator position, Args&& ...args)\n{\n  const size_type elems_before = position - begin_;\n  value_type value_copy = value_type(mystl::forward<Args>(args)...);\n  if (elems_before < (size() / 2))\n  { // 在前半段插入\n    emplace_front(front());\n    auto front1 = begin_;\n    ++front1;\n    auto front2 = front1;\n    ++front2;\n    position = begin_ + elems_before;\n    auto pos = position;\n    ++pos;\n    mystl::copy(front2, pos, front1);\n  }\n  else\n  { // 在后半段插入\n    emplace_back(back());\n    auto back1 = end_;\n    --back1;\n    auto back2 = back1;\n    --back2;\n    position = begin_ + elems_before;\n    mystl::copy_backward(position, back2, back1);\n  }\n  *position = mystl::move(value_copy);\n  return position;\n}\n\n// fill_insert 函数\ntemplate <class T>\nvoid deque<T>::\nfill_insert(iterator position, size_type n, const value_type& value)\n{\n  const size_type elems_before = position - begin_;\n  const size_type len = size();\n  auto value_copy = value;\n  if (elems_before < (len / 2))\n  {\n    require_capacity(n, true);\n    // 原来的迭代器可能会失效\n    auto old_begin = begin_;\n    auto new_begin = begin_ - n;\n    position = begin_ + elems_before;\n    try\n    {\n      if (elems_before >= n)\n      {\n        auto begin_n = begin_ + n;\n        mystl::uninitialized_copy(begin_, begin_n, new_begin);\n        begin_ = new_begin;\n        mystl::copy(begin_n, position, old_begin);\n        mystl::fill(position - n, position, value_copy);\n      }\n      else\n      {\n        mystl::uninitialized_fill(\n          mystl::uninitialized_copy(begin_, position, new_begin), begin_, value_copy);\n        begin_ = new_begin;\n        mystl::fill(old_begin, position, value_copy);\n      }\n    }\n    catch (...)\n    {\n      if (new_begin.node != begin_.node)\n        destroy_buffer(new_begin.node, begin_.node - 1);\n      throw;\n    }\n  }\n  else\n  {\n    require_capacity(n, false);\n    // 原来的迭代器可能会失效\n    auto old_end = end_;\n    auto new_end = end_ + n;\n    const size_type elems_after = len - elems_before;\n    position = end_ - elems_after;\n    try\n    {\n      if (elems_after > n)\n      {\n        auto end_n = end_ - n;\n        mystl::uninitialized_copy(end_n, end_, end_);\n        end_ = new_end;\n        mystl::copy_backward(position, end_n, old_end);\n        mystl::fill(position, position + n, value_copy);\n      }\n      else\n      {\n        mystl::uninitialized_fill(end_, position + n, value_copy);\n        mystl::uninitialized_copy(position, end_, position + n);\n        end_ = new_end;\n        mystl::fill(position, old_end, value_copy);\n      }\n    }\n    catch (...)\n    {\n      if(new_end.node != end_.node)\n        destroy_buffer(end_.node + 1, new_end.node);\n      throw;\n    }\n  }\n}\n\n// copy_insert\ntemplate <class T>\ntemplate <class FIter>\nvoid deque<T>::\ncopy_insert(iterator position, FIter first, FIter last, size_type n)\n{\n  const size_type elems_before = position - begin_;\n  auto len = size();\n  if (elems_before < (len / 2))\n  {\n    require_capacity(n, true);\n    // 原来的迭代器可能会失效\n    auto old_begin = begin_;\n    auto new_begin = begin_ - n;\n    position = begin_ + elems_before;\n    try\n    {\n      if (elems_before >= n)\n      {\n        auto begin_n = begin_ + n;\n        mystl::uninitialized_copy(begin_, begin_n, new_begin);\n        begin_ = new_begin;\n        mystl::copy(begin_n, position, old_begin);\n        mystl::copy(first, last, position - n);\n      }\n      else\n      {\n        auto mid = first;\n        mystl::advance(mid, n - elems_before);\n        mystl::uninitialized_copy(first, mid,\n                                  mystl::uninitialized_copy(begin_, position, new_begin));\n        begin_ = new_begin;\n        mystl::copy(mid, last, old_begin);\n      }\n    }\n    catch (...)\n    {\n      if(new_begin.node != begin_.node)\n        destroy_buffer(new_begin.node, begin_.node - 1);\n      throw;\n    }\n  }\n  else\n  {\n    require_capacity(n, false);\n    // 原来的迭代器可能会失效\n    auto old_end = end_;\n    auto new_end = end_ + n;\n    const auto elems_after = len - elems_before;\n    position = end_ - elems_after;\n    try\n    {\n      if (elems_after > n)\n      {\n        auto end_n = end_ - n;\n        mystl::uninitialized_copy(end_n, end_, end_);\n        end_ = new_end;\n        mystl::copy_backward(position, end_n, old_end);\n        mystl::copy(first, last, position);\n      }\n      else\n      {\n        auto mid = first;\n        mystl::advance(mid, elems_after);\n        mystl::uninitialized_copy(position, end_,\n                                  mystl::uninitialized_copy(mid, last, end_));\n        end_ = new_end;\n        mystl::copy(first, mid, position);\n      }\n    }\n    catch (...)\n    {\n      if(new_end.node != end_.node)\n        destroy_buffer(end_.node + 1, new_end.node);\n      throw;\n    }\n  }\n}\n\n// insert_dispatch 函数\ntemplate <class T>\ntemplate <class IIter>\nvoid deque<T>::\ninsert_dispatch(iterator position, IIter first, IIter last, input_iterator_tag)\n{\n  if (last <= first)  return;\n  const size_type n = mystl::distance(first, last);\n  const size_type elems_before = position - begin_;\n  if (elems_before < (size() / 2))\n  {\n    require_capacity(n, true);\n  }\n  else\n  {\n    require_capacity(n, false);\n  }\n  position = begin_ + elems_before;\n  auto cur = --last;\n  for (size_type i = 0; i < n; ++i, --cur)\n  {\n    insert(position, *cur);\n  }\n}\n\ntemplate <class T>\ntemplate <class FIter>\nvoid deque<T>::\ninsert_dispatch(iterator position, FIter first, FIter last, forward_iterator_tag)\n{\n  if (last <= first)  return;\n  const size_type n = mystl::distance(first, last);\n  if (position.cur == begin_.cur)\n  {\n    require_capacity(n, true);\n    auto new_begin = begin_ - n;\n    try\n    {\n      mystl::uninitialized_copy(first, last, new_begin);\n      begin_ = new_begin;\n    }\n    catch (...)\n    {\n      if(new_begin.node != begin_.node)\n        destroy_buffer(new_begin.node, begin_.node - 1);\n      throw;\n    }\n  }\n  else if (position.cur == end_.cur)\n  {\n    require_capacity(n, false);\n    auto new_end = end_ + n;\n    try\n    {\n      mystl::uninitialized_copy(first, last, end_);\n      end_ = new_end;\n    }\n    catch (...)\n    {\n      if(new_end.node != end_.node)\n        destroy_buffer(end_.node + 1, new_end.node);\n      throw;\n    }\n  }\n  else\n  {\n    copy_insert(position, first, last, n);\n  }\n}\n\n// require_capacity 函数\ntemplate <class T>\nvoid deque<T>::require_capacity(size_type n, bool front)\n{\n  if (front && (static_cast<size_type>(begin_.cur - begin_.first) < n))\n  {\n    const size_type need_buffer = (n - (begin_.cur - begin_.first)) / buffer_size + 1;\n    if (need_buffer > static_cast<size_type>(begin_.node - map_))\n    {\n      reallocate_map_at_front(need_buffer);\n      return;\n    }\n    create_buffer(begin_.node - need_buffer, begin_.node - 1);\n  }\n  else if (!front && (static_cast<size_type>(end_.last - end_.cur - 1) < n))\n  {\n    const size_type need_buffer = (n - (end_.last - end_.cur - 1)) / buffer_size + 1;\n    if (need_buffer > static_cast<size_type>((map_ + map_size_) - end_.node - 1))\n    {\n      reallocate_map_at_back(need_buffer);\n      return;\n    }\n    create_buffer(end_.node + 1, end_.node + need_buffer);\n  }\n}\n\n// reallocate_map_at_front 函数\ntemplate <class T>\nvoid deque<T>::reallocate_map_at_front(size_type need_buffer)\n{\n  const size_type new_map_size = mystl::max(map_size_ << 1,\n                                            map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE);\n  map_pointer new_map = create_map(new_map_size);\n  const size_type old_buffer = end_.node - begin_.node + 1;\n  const size_type new_buffer = old_buffer + need_buffer;\n\n  // 另新的 map 中的指针指向原来的 buffer，并开辟新的 buffer\n  auto begin = new_map + (new_map_size - new_buffer) / 2;\n  auto mid = begin + need_buffer;\n  auto end = mid + old_buffer;\n  create_buffer(begin, mid - 1);\n  for (auto begin1 = mid, begin2 = begin_.node; begin1 != end; ++begin1, ++begin2)\n    *begin1 = *begin2;\n\n  // 更新数据\n  map_allocator::deallocate(map_, map_size_);\n  map_ = new_map;\n  map_size_ = new_map_size;\n  begin_ = iterator(*mid + (begin_.cur - begin_.first), mid);\n  end_ = iterator(*(end - 1) + (end_.cur - end_.first), end - 1);\n}\n\n// reallocate_map_at_back 函数\ntemplate <class T>\nvoid deque<T>::reallocate_map_at_back(size_type need_buffer)\n{\n  const size_type new_map_size = mystl::max(map_size_ << 1,\n                                            map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE);\n  map_pointer new_map = create_map(new_map_size);\n  const size_type old_buffer = end_.node - begin_.node + 1;\n  const size_type new_buffer = old_buffer + need_buffer;\n\n  // 另新的 map 中的指针指向原来的 buffer，并开辟新的 buffer\n  auto begin = new_map + ((new_map_size - new_buffer) / 2);\n  auto mid = begin + old_buffer;\n  auto end = mid + need_buffer;\n  for (auto begin1 = begin, begin2 = begin_.node; begin1 != mid; ++begin1, ++begin2)\n    *begin1 = *begin2;\n  create_buffer(mid, end - 1);\n\n  // 更新数据\n  map_allocator::deallocate(map_, map_size_);\n  map_ = new_map;\n  map_size_ = new_map_size;\n  begin_ = iterator(*begin + (begin_.cur - begin_.first), begin);\n  end_ = iterator(*(mid - 1) + (end_.cur - end_.first), mid - 1);\n}\n\n// 重载比较操作符\ntemplate <class T>\nbool operator==(const deque<T>& lhs, const deque<T>& rhs)\n{\n  return lhs.size() == rhs.size() && \n    mystl::equal(lhs.begin(), lhs.end(), rhs.begin());\n}\n\ntemplate <class T>\nbool operator<(const deque<T>& lhs, const deque<T>& rhs)\n{\n  return mystl::lexicographical_compare(\n    lhs.begin(), lhs.end(), rhs.begin(), rhs.end());\n}\n\ntemplate <class T>\nbool operator!=(const deque<T>& lhs, const deque<T>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class T>\nbool operator>(const deque<T>& lhs, const deque<T>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class T>\nbool operator<=(const deque<T>& lhs, const deque<T>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class T>\nbool operator>=(const deque<T>& lhs, const deque<T>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class T>\nvoid swap(deque<T>& lhs, deque<T>& rhs)\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_DEQUE_H_\n\n"
  },
  {
    "path": "MyTinySTL/exceptdef.h",
    "content": "#ifndef MYTINYSTL_EXCEPTDEF_H_\n#define MYTINYSTL_EXCEPTDEF_H_\n\n#include <stdexcept>\n\n#include <cassert>\n\nnamespace mystl\n{\n\n#define MYSTL_DEBUG(expr) \\\n  assert(expr)  \n\n#define THROW_LENGTH_ERROR_IF(expr, what) \\\n  if ((expr)) throw std::length_error(what)\n\n#define THROW_OUT_OF_RANGE_IF(expr, what) \\\n  if ((expr)) throw std::out_of_range(what)\n\n#define THROW_RUNTIME_ERROR_IF(expr, what) \\\n  if ((expr)) throw std::runtime_error(what)\n\n} // namepsace mystl\n\n#endif // !MYTINYSTL_EXCEPTDEF_H_\n\n"
  },
  {
    "path": "MyTinySTL/functional.h",
    "content": "﻿#ifndef MYTINYSTL_FUNCTIONAL_H_\n#define MYTINYSTL_FUNCTIONAL_H_\n\n// 这个头文件包含了 mystl 的函数对象与哈希函数\n\n#include <cstddef>\n\nnamespace mystl\n{\n\n// 定义一元函数的参数型别和返回值型别\ntemplate <class Arg, class Result>\nstruct unarg_function\n{\n  typedef Arg       argument_type;\n  typedef Result    result_type;\n};\n\n// 定义二元函数的参数型别的返回值型别\ntemplate <class Arg1, class Arg2, class Result>\nstruct binary_function\n{\n  typedef Arg1      first_argument_type;\n  typedef Arg2      second_argument_type;\n  typedef Result    result_type;\n};\n\n// 函数对象：加法\ntemplate <class T>\nstruct plus :public binary_function<T, T, T>\n{\n  T operator()(const T& x, const T& y) const { return x + y; }\n};\n\n// 函数对象：减法\ntemplate <class T>\nstruct minus :public binary_function<T, T, T>\n{\n  T operator()(const T& x, const T& y) const { return x - y; }\n};\n\n// 函数对象：乘法\ntemplate <class T>\nstruct multiplies :public binary_function<T, T, T>\n{\n  T operator()(const T& x, const T& y) const { return x * y; }\n};\n\n// 函数对象：除法\ntemplate <class T>\nstruct divides :public binary_function<T, T, T>\n{\n  T operator()(const T& x, const T& y) const { return x / y; }\n};\n\n// 函数对象：模取\ntemplate <class T>\nstruct modulus :public binary_function<T, T, T>\n{\n  T operator()(const T& x, const T& y) const { return x % y; }\n};\n\n// 函数对象：否定\ntemplate <class T>\nstruct negate :public unarg_function<T, T>\n{\n  T operator()(const T& x) const { return -x; }\n};\n\n// 加法的证同元素\ntemplate <class T>\nT identity_element(plus<T>) { return T(0); }\n\n// 乘法的证同元素\ntemplate <class T>\nT identity_element(multiplies<T>) { return T(1); }\n\n// 函数对象：等于\ntemplate <class T>\nstruct equal_to :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x == y; }\n};\n\n// 函数对象：不等于\ntemplate <class T>\nstruct not_equal_to :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x != y; }\n};\n\n// 函数对象：大于\ntemplate <class T>\nstruct greater :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x > y; }\n};\n\n// 函数对象：小于\ntemplate <class T>\nstruct less :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x < y; }\n};\n\n// 函数对象：大于等于\ntemplate <class T>\nstruct greater_equal :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x >= y; }\n};\n\n// 函数对象：小于等于\ntemplate <class T>\nstruct less_equal :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x <= y; }\n};\n\n// 函数对象：逻辑与\ntemplate <class T>\nstruct logical_and :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x && y; }\n};\n\n// 函数对象：逻辑或\ntemplate <class T>\nstruct logical_or :public binary_function<T, T, bool>\n{\n  bool operator()(const T& x, const T& y) const { return x || y; }\n};\n\n// 函数对象：逻辑非\ntemplate <class T>\nstruct logical_not :public unarg_function<T, bool>\n{\n  bool operator()(const T& x) const { return !x; }\n};\n\n// 证同函数：不会改变元素，返回本身\ntemplate <class T>\nstruct identity :public unarg_function<T, bool>\n{\n  const T& operator()(const T& x) const { return x; }\n};\n\n// 选择函数：接受一个 pair，返回第一个元素\ntemplate <class Pair>\nstruct selectfirst :public unarg_function<Pair, typename Pair::first_type>\n{\n  const typename Pair::first_type& operator()(const Pair& x) const\n  {\n    return x.first;\n  }\n};\n\n// 选择函数：接受一个 pair，返回第二个元素\ntemplate <class Pair>\nstruct selectsecond :public unarg_function<Pair, typename Pair::second_type>\n{\n  const typename Pair::second_type& operator()(const Pair& x) const\n  {\n    return x.second;\n  }\n};\n\n// 投射函数：返回第一参数\ntemplate <class Arg1, class Arg2>\nstruct projectfirst :public binary_function<Arg1, Arg2, Arg1>\n{\n  Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }\n};\n\n// 投射函数：返回第二参数\ntemplate <class Arg1, class Arg2>\nstruct projectsecond :public binary_function<Arg1, Arg2, Arg1>\n{\n  Arg2 operator()(const Arg1&, const Arg2& y) const { return y; }\n};\n\n/*****************************************************************************************/\n// 哈希函数对象\n\n// 对于大部分类型，hash function 什么都不做\ntemplate <class Key>\nstruct hash {};\n\n// 针对指针的偏特化版本\ntemplate <class T>\nstruct hash<T*>\n{\n  size_t operator()(T* p) const noexcept\n  { return reinterpret_cast<size_t>(p); }\n};\n\n// 对于整型类型，只是返回原值\n#define MYSTL_TRIVIAL_HASH_FCN(Type)         \\\ntemplate <> struct hash<Type>                \\\n{                                            \\\n  size_t operator()(Type val) const noexcept \\\n  { return static_cast<size_t>(val); }       \\\n};\n\nMYSTL_TRIVIAL_HASH_FCN(bool)\n\nMYSTL_TRIVIAL_HASH_FCN(char)\n\nMYSTL_TRIVIAL_HASH_FCN(signed char)\n\nMYSTL_TRIVIAL_HASH_FCN(unsigned char)\n\nMYSTL_TRIVIAL_HASH_FCN(wchar_t)\n\nMYSTL_TRIVIAL_HASH_FCN(char16_t)\n\nMYSTL_TRIVIAL_HASH_FCN(char32_t)\n\nMYSTL_TRIVIAL_HASH_FCN(short)\n\nMYSTL_TRIVIAL_HASH_FCN(unsigned short)\n\nMYSTL_TRIVIAL_HASH_FCN(int)\n\nMYSTL_TRIVIAL_HASH_FCN(unsigned int)\n\nMYSTL_TRIVIAL_HASH_FCN(long)\n\nMYSTL_TRIVIAL_HASH_FCN(unsigned long)\n\nMYSTL_TRIVIAL_HASH_FCN(long long)\n\nMYSTL_TRIVIAL_HASH_FCN(unsigned long long)\n\n#undef MYSTL_TRIVIAL_HASH_FCN\n\n// 对于浮点数，逐位哈希\ninline size_t bitwise_hash(const unsigned char* first, size_t count)\n{\n#if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) &&__SIZEOF_POINTER__ == 8)\n  const size_t fnv_offset = 14695981039346656037ull;\n  const size_t fnv_prime = 1099511628211ull;\n#else\n  const size_t fnv_offset = 2166136261u;\n  const size_t fnv_prime = 16777619u;\n#endif\n  size_t result = fnv_offset;\n  for (size_t i = 0; i < count; ++i)\n  {\n    result ^= (size_t)first[i];\n    result *= fnv_prime;\n  }\n  return result;\n}\n\ntemplate <>\nstruct hash<float>\n{\n  size_t operator()(const float& val)\n  { \n    return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(float));\n  }\n};\n\ntemplate <>\nstruct hash<double>\n{\n  size_t operator()(const double& val)\n  {\n    return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(double));\n  }\n};\n\ntemplate <>\nstruct hash<long double>\n{\n  size_t operator()(const long double& val)\n  {\n    return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(long double));\n  }\n};\n\n} // namespace mystl\n#endif // !MYTINYSTL_FUNCTIONAL_H_\n\n"
  },
  {
    "path": "MyTinySTL/hashtable.h",
    "content": "﻿#ifndef MYTINYSTL_HASHTABLE_H_\n#define MYTINYSTL_HASHTABLE_H_\n\n// 这个头文件包含了一个模板类 hashtable\n// hashtable : 哈希表，使用开链法处理冲突\n\n#include <initializer_list>\n\n#include \"algo.h\"\n#include \"functional.h\"\n#include \"memory.h\"\n#include \"vector.h\"\n#include \"util.h\"\n#include \"exceptdef.h\"\n\nnamespace mystl\n{\n\n// hashtable 的节点定义\ntemplate <class T>\nstruct hashtable_node\n{\n  hashtable_node* next;   // 指向下一个节点\n  T               value;  // 储存实值\n\n  hashtable_node() = default;\n  hashtable_node(const T& n) :next(nullptr), value(n) {}\n\n  hashtable_node(const hashtable_node& node) :next(node.next), value(node.value) {}\n  hashtable_node(hashtable_node&& node) :next(node.next), value(mystl::move(node.value))\n  {\n    node.next = nullptr;\n  }\n};\n\n// value traits\ntemplate <class T, bool>\nstruct ht_value_traits_imp\n{\n  typedef T key_type;\n  typedef T mapped_type;\n  typedef T value_type;\n\n  template <class Ty>\n  static const key_type& get_key(const Ty& value)\n  {\n    return value;\n  }\n\n  template <class Ty>\n  static const value_type& get_value(const Ty& value)\n  {\n    return value;\n  }\n};\n\ntemplate <class T>\nstruct ht_value_traits_imp<T, true>\n{\n  typedef typename std::remove_cv<typename T::first_type>::type key_type;\n  typedef typename T::second_type                               mapped_type;\n  typedef T                                                     value_type;\n\n  template <class Ty>\n  static const key_type& get_key(const Ty& value)\n  {\n    return value.first;\n  }\n\n  template <class Ty>\n  static const value_type& get_value(const Ty& value)\n  {\n    return value;\n  }\n};\n\ntemplate <class T>\nstruct ht_value_traits\n{\n  static constexpr bool is_map = mystl::is_pair<T>::value;\n\n  typedef ht_value_traits_imp<T, is_map> value_traits_type;\n\n  typedef typename value_traits_type::key_type    key_type;\n  typedef typename value_traits_type::mapped_type mapped_type;\n  typedef typename value_traits_type::value_type  value_type;\n\n  template <class Ty>\n  static const key_type& get_key(const Ty& value)\n  {\n    return value_traits_type::get_key(value);\n  }\n\n  template <class Ty>\n  static const value_type& get_value(const Ty& value)\n  {\n    return value_traits_type::get_value(value);\n  }\n};\n\n\n// forward declaration\n\ntemplate <class T, class HashFun, class KeyEqual>\nclass hashtable;\n\ntemplate <class T, class HashFun, class KeyEqual>\nstruct ht_iterator;\n\ntemplate <class T, class HashFun, class KeyEqual>\nstruct ht_const_iterator;\n\ntemplate <class T>\nstruct ht_local_iterator;\n\ntemplate <class T>\nstruct ht_const_local_iterator;\n\n// ht_iterator\n\ntemplate <class T, class Hash, class KeyEqual>\nstruct ht_iterator_base :public mystl::iterator<mystl::forward_iterator_tag, T>\n{\n  typedef mystl::hashtable<T, Hash, KeyEqual>         hashtable;\n  typedef ht_iterator_base<T, Hash, KeyEqual>         base;\n  typedef mystl::ht_iterator<T, Hash, KeyEqual>       iterator;\n  typedef mystl::ht_const_iterator<T, Hash, KeyEqual> const_iterator;\n  typedef hashtable_node<T>*                          node_ptr;\n  typedef hashtable*                                  contain_ptr;\n  typedef const node_ptr                              const_node_ptr;\n  typedef const contain_ptr                           const_contain_ptr;\n\n  typedef size_t                                      size_type;\n  typedef ptrdiff_t                                   difference_type;\n\n  node_ptr    node;  // 迭代器当前所指节点\n  contain_ptr ht;    // 保持与容器的连结\n\n  ht_iterator_base() = default;\n\n  bool operator==(const base& rhs) const { return node == rhs.node; }\n  bool operator!=(const base& rhs) const { return node != rhs.node; }\n};\n\ntemplate <class T, class Hash, class KeyEqual>\nstruct ht_iterator :public ht_iterator_base<T, Hash, KeyEqual>\n{\n  typedef ht_iterator_base<T, Hash, KeyEqual> base;\n  typedef typename base::hashtable            hashtable;\n  typedef typename base::iterator             iterator;\n  typedef typename base::const_iterator       const_iterator;\n  typedef typename base::node_ptr             node_ptr;\n  typedef typename base::contain_ptr          contain_ptr;\n\n  typedef ht_value_traits<T>                  value_traits;\n  typedef T                                   value_type;\n  typedef value_type*                         pointer;\n  typedef value_type&                         reference;\n\n  using base::node;\n  using base::ht;\n\n  ht_iterator() = default;\n  ht_iterator(node_ptr n, contain_ptr t)\n  {\n    node = n;\n    ht = t;\n  }\n  ht_iterator(const iterator& rhs)\n  {\n    node = rhs.node;\n    ht = rhs.ht;\n  }\n  ht_iterator(const const_iterator& rhs)\n  {\n    node = rhs.node;\n    ht = rhs.ht;\n  }\n  iterator& operator=(const iterator& rhs)\n  {\n    if (this != &rhs)\n    {\n      node = rhs.node;\n      ht = rhs.ht;\n    }\n    return *this;\n  }\n  iterator& operator=(const const_iterator& rhs)\n  {\n    if (this != &rhs)\n    {\n      node = rhs.node;\n      ht = rhs.ht;\n    }\n    return *this;\n  }\n\n  // 重载操作符\n  reference operator*()  const { return node->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  iterator& operator++()\n  {\n    MYSTL_DEBUG(node != nullptr);\n    const node_ptr old = node;\n    node = node->next;\n    if (node == nullptr)\n    { // 如果下一个位置为空，跳到下一个 bucket 的起始处\n      auto index = ht->hash(value_traits::get_key(old->value));\n      while (!node && ++index < ht->bucket_size_)\n        node = ht->buckets_[index];\n    }\n    return *this;\n  }\n  iterator operator++(int)\n  {\n    iterator tmp = *this;\n    ++*this;\n    return tmp;\n  }\n};\n\ntemplate <class T, class Hash, class KeyEqual>\nstruct ht_const_iterator :public ht_iterator_base<T, Hash, KeyEqual>\n{\n  typedef ht_iterator_base<T, Hash, KeyEqual> base;\n  typedef typename base::hashtable            hashtable;\n  typedef typename base::iterator             iterator;\n  typedef typename base::const_iterator       const_iterator;\n  typedef typename base::const_node_ptr       node_ptr;\n  typedef typename base::const_contain_ptr    contain_ptr;\n\n  typedef ht_value_traits<T>                  value_traits;\n  typedef T                                   value_type;\n  typedef const value_type*                   pointer;\n  typedef const value_type&                   reference;\n\n  using base::node;\n  using base::ht;\n\n  ht_const_iterator() = default;\n  ht_const_iterator(node_ptr n, contain_ptr t)\n  {\n    node = n;\n    ht = t;\n  }\n  ht_const_iterator(const iterator& rhs)\n  {\n    node = rhs.node;\n    ht = rhs.ht;\n  }\n  ht_const_iterator(const const_iterator& rhs)\n  {\n    node = rhs.node;\n    ht = rhs.ht;\n  }\n  const_iterator& operator=(const iterator& rhs)\n  {\n    if (this != &rhs)\n    {\n      node = rhs.node;\n      ht = rhs.ht;\n    }\n    return *this;\n  }\n  const_iterator& operator=(const const_iterator& rhs)\n  {\n    if (this != &rhs)\n    {\n      node = rhs.node;\n      ht = rhs.ht;\n    }\n    return *this;\n  }\n\n  // 重载操作符\n  reference operator*()  const { return node->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  const_iterator& operator++()\n  {\n    MYSTL_DEBUG(node != nullptr);\n    const node_ptr old = node;\n    node = node->next;\n    if (node == nullptr)\n    { // 如果下一个位置为空，跳到下一个 bucket 的起始处\n      auto index = ht->hash(value_traits::get_key(old->value));\n      while (!node && ++index < ht->bucket_size_)\n      {\n        node = ht->buckets_[index];\n      }\n    }\n    return *this;\n  }\n  const_iterator operator++(int)\n  {\n    const_iterator tmp = *this;\n    ++*this;\n    return tmp;\n  }\n};\n\n// local iterator\ntemplate <class T>\nstruct ht_local_iterator :public mystl::iterator<mystl::forward_iterator_tag, T>\n{\n  typedef T                          value_type;\n  typedef value_type*                pointer;\n  typedef value_type&                reference;\n  typedef size_t                     size_type;\n  typedef ptrdiff_t                  difference_type;\n  typedef hashtable_node<T>*         node_ptr;\n\n  typedef ht_local_iterator<T>       self;\n  typedef ht_local_iterator<T>       local_iterator;\n  typedef ht_const_local_iterator<T> const_local_iterator;\n  node_ptr node;\n\n  ht_local_iterator(node_ptr n)\n    :node(n)\n  {\n  }\n  ht_local_iterator(const local_iterator& rhs)\n    :node(rhs.node)\n  {\n  }\n  ht_local_iterator(const const_local_iterator& rhs)\n    :node(rhs.node)\n  {\n  }\n\n  reference operator*()  const { return node->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  self& operator++()\n  {\n    MYSTL_DEBUG(node != nullptr);\n    node = node->next;\n    return *this;\n  }\n  \n  self operator++(int)\n  {\n    self tmp(*this);\n    ++*this;\n    return tmp;\n  }\n\n  bool operator==(const self& other) const { return node == other.node; }\n  bool operator!=(const self& other) const { return node != other.node; }\n};\n\ntemplate <class T>\nstruct ht_const_local_iterator :public mystl::iterator<mystl::forward_iterator_tag, T>\n{\n  typedef T                          value_type;\n  typedef const value_type*          pointer;\n  typedef const value_type&          reference;\n  typedef size_t                     size_type;\n  typedef ptrdiff_t                  difference_type;\n  typedef const hashtable_node<T>*   node_ptr;\n\n  typedef ht_const_local_iterator<T> self;\n  typedef ht_local_iterator<T>       local_iterator;\n  typedef ht_const_local_iterator<T> const_local_iterator;\n\n  node_ptr node;\n\n  ht_const_local_iterator(node_ptr n)\n    :node(n)\n  {\n  }\n  ht_const_local_iterator(const local_iterator& rhs)\n    :node(rhs.node)\n  {\n  }\n  ht_const_local_iterator(const const_local_iterator& rhs)\n    :node(rhs.node)\n  {\n  }\n\n  reference operator*()  const { return node->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  self& operator++()\n  {\n    MYSTL_DEBUG(node != nullptr);\n    node = node->next;\n    return *this;\n  }\n\n  self operator++(int)\n  {\n    self tmp(*this);\n    ++*this;\n    return tmp;\n  }\n\n  bool operator==(const self& other) const { return node == other.node; }\n  bool operator!=(const self& other) const { return node != other.node; }\n};\n\n// bucket 使用的大小\n\n#if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) &&__SIZEOF_POINTER__ == 8)\n#define SYSTEM_64 1\n#else\n#define SYSTEM_32 1\n#endif\n\n#ifdef SYSTEM_64\n\n#define PRIME_NUM 99\n\n// 1. start with p = 101\n// 2. p = next_prime(p * 1.7)\n// 3. if p < (2 << 63), go to step 2, otherwise, go to step 4\n// 4. end with p = prev_prime(2 << 63 - 1)\nstatic constexpr size_t ht_prime_list[] = {\n  101ull, 173ull, 263ull, 397ull, 599ull, 907ull, 1361ull, 2053ull, 3083ull,\n  4637ull, 6959ull, 10453ull, 15683ull, 23531ull, 35311ull, 52967ull, 79451ull,\n  119179ull, 178781ull, 268189ull, 402299ull, 603457ull, 905189ull, 1357787ull,\n  2036687ull, 3055043ull, 4582577ull, 6873871ull, 10310819ull, 15466229ull,\n  23199347ull, 34799021ull, 52198537ull, 78297827ull, 117446801ull, 176170229ull,\n  264255353ull, 396383041ull, 594574583ull, 891861923ull, 1337792887ull,\n  2006689337ull, 3010034021ull, 4515051137ull, 6772576709ull, 10158865069ull,\n  15238297621ull, 22857446471ull, 34286169707ull, 51429254599ull, 77143881917ull,\n  115715822899ull, 173573734363ull, 260360601547ull, 390540902329ull, \n  585811353559ull, 878717030339ull, 1318075545511ull, 1977113318311ull, \n  2965669977497ull, 4448504966249ull, 6672757449409ull, 10009136174239ull,\n  15013704261371ull, 22520556392057ull, 33780834588157ull, 50671251882247ull,\n  76006877823377ull, 114010316735089ull, 171015475102649ull, 256523212653977ull,\n  384784818980971ull, 577177228471507ull, 865765842707309ull, 1298648764060979ull,\n  1947973146091477ull, 2921959719137273ull, 4382939578705967ull, 6574409368058969ull,\n  9861614052088471ull, 14792421078132871ull, 22188631617199337ull, 33282947425799017ull,\n  49924421138698549ull, 74886631708047827ull, 112329947562071807ull, 168494921343107851ull,\n  252742382014661767ull, 379113573021992729ull, 568670359532989111ull, 853005539299483657ull,\n  1279508308949225477ull, 1919262463423838231ull, 2878893695135757317ull, 4318340542703636011ull,\n  6477510814055453699ull, 9716266221083181299ull, 14574399331624771603ull, 18446744073709551557ull\n};\n\n#else\n\n#define PRIME_NUM 44\n\n// 1. start with p = 101\n// 2. p = next_prime(p * 1.7)\n// 3. if p < (2 << 31), go to step 2, otherwise, go to step 4\n// 4. end with p = prev_prime(2 << 31 - 1)\nstatic constexpr size_t ht_prime_list[] = {\n  101u, 173u, 263u, 397u, 599u, 907u, 1361u, 2053u, 3083u, 4637u, 6959u, \n  10453u, 15683u, 23531u, 35311u, 52967u, 79451u, 119179u, 178781u, 268189u,\n  402299u, 603457u, 905189u, 1357787u, 2036687u, 3055043u, 4582577u, 6873871u,\n  10310819u, 15466229u, 23199347u, 34799021u, 52198537u, 78297827u, 117446801u,\n  176170229u, 264255353u, 396383041u, 594574583u, 891861923u, 1337792887u,\n  2006689337u, 3010034021u, 4294967291u,\n};\n\n#endif\n\n// 找出最接近并大于等于 n 的那个质数\ninline size_t ht_next_prime(size_t n)\n{\n  const size_t* first = ht_prime_list;\n  const size_t* last = ht_prime_list + PRIME_NUM;\n  const size_t* pos = mystl::lower_bound(first, last, n);\n  return pos == last ? *(last - 1) : *pos;\n}\n\n// 模板类 hashtable\n// 参数一代表数据类型，参数二代表哈希函数，参数三代表键值相等的比较函数\ntemplate <class T, class Hash, class KeyEqual>\nclass hashtable\n{  \n\n  friend struct mystl::ht_iterator<T, Hash, KeyEqual>;\n  friend struct mystl::ht_const_iterator<T, Hash, KeyEqual>;\n\npublic:\n  // hashtable 的型别定义\n  typedef ht_value_traits<T>                          value_traits;\n  typedef typename value_traits::key_type             key_type;\n  typedef typename value_traits::mapped_type          mapped_type;\n  typedef typename value_traits::value_type           value_type;\n  typedef Hash                                        hasher;\n  typedef KeyEqual                                    key_equal;\n\n  typedef hashtable_node<T>                           node_type;\n  typedef node_type*                                  node_ptr;\n  typedef mystl::vector<node_ptr>                     bucket_type;\n\n  typedef mystl::allocator<T>                         allocator_type;\n  typedef mystl::allocator<T>                         data_allocator;\n  typedef mystl::allocator<node_type>                 node_allocator;\n\n  typedef typename allocator_type::pointer            pointer;\n  typedef typename allocator_type::const_pointer      const_pointer;\n  typedef typename allocator_type::reference          reference;\n  typedef typename allocator_type::const_reference    const_reference;\n  typedef typename allocator_type::size_type          size_type;\n  typedef typename allocator_type::difference_type    difference_type;\n\n  typedef mystl::ht_iterator<T, Hash, KeyEqual>       iterator;\n  typedef mystl::ht_const_iterator<T, Hash, KeyEqual> const_iterator;\n  typedef mystl::ht_local_iterator<T>                 local_iterator;\n  typedef mystl::ht_const_local_iterator<T>           const_local_iterator;\n\n  allocator_type get_allocator() const { return allocator_type(); }\n\nprivate:\n  // 用以下六个参数来表现 hashtable\n  bucket_type buckets_;\n  size_type   bucket_size_;\n  size_type   size_;\n  float       mlf_;\n  hasher      hash_;\n  key_equal   equal_;\n\nprivate:\n  bool is_equal(const key_type& key1, const key_type& key2)\n  {\n    return equal_(key1, key2);\n  }\n\n  bool is_equal(const key_type& key1, const key_type& key2) const\n  {\n    return equal_(key1, key2);\n  }\n\n  const_iterator M_cit(node_ptr node) const noexcept\n  {\n    return const_iterator(node, const_cast<hashtable*>(this));\n  }\n\n  iterator M_begin() noexcept\n  {\n    for (size_type n = 0; n < bucket_size_; ++n)\n    {\n      if (buckets_[n])  // 找到第一个有节点的位置就返回\n        return iterator(buckets_[n], this);\n    }\n    return iterator(nullptr, this);\n  }\n\n  const_iterator M_begin() const noexcept\n  {\n    for (size_type n = 0; n < bucket_size_; ++n)\n    {\n      if (buckets_[n])  // 找到第一个有节点的位置就返回\n        return M_cit(buckets_[n]);\n    }\n    return M_cit(nullptr);\n  }\n\npublic:\n  // 构造、复制、移动、析构函数\n  explicit hashtable(size_type bucket_count,\n                     const Hash& hash = Hash(),\n                     const KeyEqual& equal = KeyEqual())\n    :size_(0), mlf_(1.0f), hash_(hash), equal_(equal)\n  {\n    init(bucket_count);\n  }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n    hashtable(Iter first, Iter last,\n              size_type bucket_count,\n              const Hash& hash = Hash(),\n              const KeyEqual& equal = KeyEqual())\n    :size_(mystl::distance(first, last)), mlf_(1.0f), hash_(hash), equal_(equal)\n  {\n    init(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))));\n  }\n\n  hashtable(const hashtable& rhs)\n    :hash_(rhs.hash_), equal_(rhs.equal_)\n  {\n    copy_init(rhs);\n  }\n  hashtable(hashtable&& rhs) noexcept\n    : bucket_size_(rhs.bucket_size_), \n    size_(rhs.size_),\n    mlf_(rhs.mlf_),\n    hash_(rhs.hash_),\n    equal_(rhs.equal_)\n  {\n    buckets_ = mystl::move(rhs.buckets_);\n    rhs.bucket_size_ = 0;\n    rhs.size_ = 0;\n    rhs.mlf_ = 0.0f;\n  }\n\n  hashtable& operator=(const hashtable& rhs);\n  hashtable& operator=(hashtable&& rhs) noexcept;\n\n  ~hashtable() { clear(); }\n\n  // 迭代器相关操作\n  iterator       begin()        noexcept\n  { return M_begin(); }\n  const_iterator begin()  const noexcept\n  { return M_begin(); }\n  iterator       end()          noexcept\n  { return iterator(nullptr, this); }\n  const_iterator end()    const noexcept\n  { return M_cit(nullptr); }\n  \n  const_iterator cbegin() const noexcept\n  { return begin(); }\n  const_iterator cend()   const noexcept\n  { return end(); }\n\n  // 容量相关操作\n  bool      empty()    const noexcept { return size_ == 0; }\n  size_type size()     const noexcept { return size_; }\n  size_type max_size() const noexcept { return static_cast<size_type>(-1); }\n\n  // 修改容器相关操作\n\n  // emplace / empalce_hint\n\n  template <class ...Args>\n  iterator emplace_multi(Args&& ...args);\n\n  template <class ...Args>\n  pair<iterator, bool> emplace_unique(Args&& ...args);\n\n  // [note]: hint 对于 hash_table 其实没有意义，因为即使提供了 hint，也要做一次 hash，\n  // 来确保 hash_table 的性质，所以选择忽略它\n  template <class ...Args>\n  iterator emplace_multi_use_hint(const_iterator /*hint*/, Args&& ...args)\n  { return emplace_multi(mystl::forward<Args>(args)...); }\n\n  template <class ...Args>\n  iterator emplace_unique_use_hint(const_iterator /*hint*/, Args&& ...args)\n  { return emplace_unique(mystl::forward<Args>(args)...).first; }\n\n  // insert\n\n  iterator             insert_multi_noresize(const value_type& value);\n  pair<iterator, bool> insert_unique_noresize(const value_type& value);\n\n  iterator insert_multi(const value_type& value)\n  {\n    rehash_if_need(1);\n    return insert_multi_noresize(value);\n  }\n  iterator insert_multi(value_type&& value)\n  { return emplace_multi(mystl::move(value)); }\n\n\n  pair<iterator, bool> insert_unique(const value_type& value)\n  {\n    rehash_if_need(1);\n    return insert_unique_noresize(value);\n  }\n  pair<iterator, bool> insert_unique(value_type&& value)\n  { return emplace_unique(mystl::move(value)); }\n\n  // [note]: 同 emplace_hint\n  iterator insert_multi_use_hint(const_iterator /*hint*/, const value_type& value)\n  { return insert_multi(value); }\n  iterator insert_multi_use_hint(const_iterator /*hint*/, value_type&& value)\n  { return emplace_multi(mystl::move(value)); }\n\n  iterator insert_unique_use_hint(const_iterator /*hint*/, const value_type& value)\n  { return insert_unique(value).first; }\n  iterator insert_unique_use_hint(const_iterator /*hint*/, value_type&& value)\n  { return emplace_unique(mystl::move(value)); }\n\n  template <class InputIter>\n  void insert_multi(InputIter first, InputIter last)\n  { copy_insert_multi(first, last, iterator_category(first)); }\n\n  template <class InputIter>\n  void insert_unique(InputIter first, InputIter last)\n  { copy_insert_unique(first, last, iterator_category(first)); }\n\n  // erase / clear\n\n  void      erase(const_iterator position);\n  void      erase(const_iterator first, const_iterator last);\n\n  size_type erase_multi(const key_type& key);\n  size_type erase_unique(const key_type& key);\n\n  void      clear();\n\n  void      swap(hashtable& rhs) noexcept;\n\n  // 查找相关操作\n\n  size_type                            count(const key_type& key) const;\n\n  iterator                             find(const key_type& key);\n  const_iterator                       find(const key_type& key) const;\n\n  pair<iterator, iterator>             equal_range_multi(const key_type& key);\n  pair<const_iterator, const_iterator> equal_range_multi(const key_type& key) const;\n\n  pair<iterator, iterator>             equal_range_unique(const key_type& key);\n  pair<const_iterator, const_iterator> equal_range_unique(const key_type& key) const;\n\n  // bucket interface\n\n  local_iterator       begin(size_type n)        noexcept\n  { \n    MYSTL_DEBUG(n < size_);\n    return buckets_[n];\n  }\n  const_local_iterator begin(size_type n)  const noexcept\n  { \n    MYSTL_DEBUG(n < size_);\n    return buckets_[n];\n  }\n  const_local_iterator cbegin(size_type n) const noexcept\n  { \n    MYSTL_DEBUG(n < size_);\n    return buckets_[n];\n  }\n\n  local_iterator       end(size_type n)          noexcept\n  { \n    MYSTL_DEBUG(n < size_);\n    return nullptr; \n  }\n  const_local_iterator end(size_type n)    const noexcept\n  { \n    MYSTL_DEBUG(n < size_);\n    return nullptr; \n  }\n  const_local_iterator cend(size_type n)   const noexcept\n  {\n    MYSTL_DEBUG(n < size_);\n    return nullptr; \n  }\n\n  size_type bucket_count()                 const noexcept\n  { return bucket_size_; }\n  size_type max_bucket_count()             const noexcept\n  { return ht_prime_list[PRIME_NUM - 1]; }\n\n  size_type bucket_size(size_type n)       const noexcept;\n  size_type bucket(const key_type& key)    const\n  { return hash(key); }\n\n  // hash policy\n\n  float load_factor() const noexcept\n  { return bucket_size_ != 0 ? (float)size_ / bucket_size_ : 0.0f; }\n\n  float max_load_factor() const noexcept\n  { return mlf_; }\n  void max_load_factor(float ml)\n  {\n    THROW_OUT_OF_RANGE_IF(ml != ml || ml < 0, \"invalid hash load factor\");\n    mlf_ = ml;\n  }\n\n  void rehash(size_type count);\n\n  void reserve(size_type count)\n  { rehash(static_cast<size_type>((float)count / max_load_factor() + 0.5f)); }\n\n  hasher    hash_fcn() const { return hash_; }\n  key_equal key_eq()   const { return equal_; }\n\nprivate:\n  // hashtable 成员函数\n\n  // init\n  void      init(size_type n);\n  void      copy_init(const hashtable& ht);\n\n  // node\n  template  <class ...Args>\n  node_ptr  create_node(Args&& ...args);\n  void      destroy_node(node_ptr n);\n\n  // hash\n  size_type next_size(size_type n) const;\n  size_type hash(const key_type& key, size_type n) const;\n  size_type hash(const key_type& key) const;\n  void      rehash_if_need(size_type n);\n\n  // insert\n  template <class InputIter>\n  void copy_insert_multi(InputIter first, InputIter last, mystl::input_iterator_tag);\n  template <class ForwardIter>\n  void copy_insert_multi(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag);\n  template <class InputIter>\n  void copy_insert_unique(InputIter first, InputIter last, mystl::input_iterator_tag);\n  template <class ForwardIter>\n  void copy_insert_unique(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag);\n\n  // insert node\n  pair<iterator, bool> insert_node_unique(node_ptr np);\n  iterator             insert_node_multi(node_ptr np);\n\n  // bucket operator\n  void replace_bucket(size_type bucket_count);\n  void erase_bucket(size_type n, node_ptr first, node_ptr last);\n  void erase_bucket(size_type n, node_ptr last);\n\n  // comparision\n  bool equal_to_multi(const hashtable& other);\n  bool equal_to_unique(const hashtable& other);\n};\n\n/*****************************************************************************************/\n\n// 复制赋值运算符\ntemplate <class T, class Hash, class KeyEqual>\nhashtable<T, Hash, KeyEqual>&\nhashtable<T, Hash, KeyEqual>::\noperator=(const hashtable& rhs)\n{\n  if (this != &rhs)\n  {\n    hashtable tmp(rhs);\n    swap(tmp);\n  }\n  return *this;\n}\n\n// 移动赋值运算符\ntemplate <class T, class Hash, class KeyEqual>\nhashtable<T, Hash, KeyEqual>&\nhashtable<T, Hash, KeyEqual>::\noperator=(hashtable&& rhs) noexcept\n{\n  hashtable tmp(mystl::move(rhs));\n  swap(tmp);\n  return *this;\n}\n\n// 就地构造元素，键值允许重复\n// 强异常安全保证\ntemplate <class T, class Hash, class KeyEqual>\ntemplate <class ...Args>\ntypename hashtable<T, Hash, KeyEqual>::iterator\nhashtable<T, Hash, KeyEqual>::\nemplace_multi(Args&& ...args)\n{\n  auto np = create_node(mystl::forward<Args>(args)...);\n  try\n  {\n    if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor())\n      rehash(size_ + 1);\n  }\n  catch (...)\n  {\n    destroy_node(np);\n    throw;\n  }\n  return insert_node_multi(np);\n}\n\n// 就地构造元素，键值允许重复\n// 强异常安全保证\ntemplate <class T, class Hash, class KeyEqual>\ntemplate <class ...Args>\npair<typename hashtable<T, Hash, KeyEqual>::iterator, bool> \nhashtable<T, Hash, KeyEqual>::\nemplace_unique(Args&& ...args)\n{\n  auto np = create_node(mystl::forward<Args>(args)...);\n  try\n  {\n    if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor())\n      rehash(size_ + 1);\n  }\n  catch (...)\n  {\n    destroy_node(np);\n    throw;\n  }\n  return insert_node_unique(np);\n}\n\n// 在不需要重建表格的情况下插入新节点，键值不允许重复\ntemplate <class T, class Hash, class KeyEqual>\npair<typename hashtable<T, Hash, KeyEqual>::iterator, bool>\nhashtable<T, Hash, KeyEqual>::\ninsert_unique_noresize(const value_type& value)\n{\n  const auto n = hash(value_traits::get_key(value));\n  auto first = buckets_[n];\n  for (auto cur = first; cur; cur = cur->next)\n  {\n    if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(value)))\n      return mystl::make_pair(iterator(cur, this), false);\n  }\n  // 让新节点成为链表的第一个节点\n  auto tmp = create_node(value);  \n  tmp->next = first;\n  buckets_[n] = tmp;\n  ++size_;\n  return mystl::make_pair(iterator(tmp, this), true);\n}\n\n// 在不需要重建表格的情况下插入新节点，键值允许重复\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::iterator\nhashtable<T, Hash, KeyEqual>::\ninsert_multi_noresize(const value_type& value)\n{\n  const auto n = hash(value_traits::get_key(value));\n  auto first = buckets_[n];\n  auto tmp = create_node(value);\n  for (auto cur = first; cur; cur = cur->next)\n  {\n    if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(value)))\n    { // 如果链表中存在相同键值的节点就马上插入，然后返回\n      tmp->next = cur->next;\n      cur->next = tmp;\n      ++size_;\n      return iterator(tmp, this);\n    }\n  }\n  // 否则插入在链表头部\n  tmp->next = first;\n  buckets_[n] = tmp;\n  ++size_;\n  return iterator(tmp, this);\n}\n\n// 删除迭代器所指的节点\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nerase(const_iterator position)\n{\n  auto p = position.node;\n  if (p)\n  {\n    const auto n = hash(value_traits::get_key(p->value));\n    auto cur = buckets_[n];\n    if (cur == p)\n    { // p 位于链表头部\n      buckets_[n] = cur->next;\n      destroy_node(cur);\n      --size_;\n    }\n    else\n    {\n      auto next = cur->next;\n      while (next)\n      {\n        if (next == p)\n        {\n          cur->next = next->next;\n          destroy_node(next);\n          --size_;\n          break;\n        }\n        else\n        {\n          cur = next;\n          next = cur->next;\n        }\n      }\n    }\n  }\n}\n\n// 删除[first, last)内的节点\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nerase(const_iterator first, const_iterator last)\n{\n  if (first.node == last.node)\n    return;\n  auto first_bucket = first.node \n    ? hash(value_traits::get_key(first.node->value)) \n    : bucket_size_;\n  auto last_bucket = last.node \n    ? hash(value_traits::get_key(last.node->value))\n    : bucket_size_;\n  if (first_bucket == last_bucket)\n  { // 如果在 bucket 在同一个位置\n    erase_bucket(first_bucket, first.node, last.node);\n  }\n  else\n  {\n    erase_bucket(first_bucket, first.node, nullptr);\n    for (auto n = first_bucket + 1; n < last_bucket; ++n)\n    {\n      if(buckets_[n] != nullptr)\n        erase_bucket(n, nullptr);\n    }\n    if (last_bucket != bucket_size_)\n    {\n      erase_bucket(last_bucket, last.node);\n    }\n  }\n}\n\n// 删除键值为 key 的节点\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::size_type\nhashtable<T, Hash, KeyEqual>::\nerase_multi(const key_type& key)\n{\n  auto p = equal_range_multi(key);\n  if (p.first.node != nullptr)\n  {\n    erase(p.first, p.second);\n    return mystl::distance(p.first, p.second);\n  }\n  return 0;\n}\n\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::size_type\nhashtable<T, Hash, KeyEqual>::\nerase_unique(const key_type& key)\n{\n  const auto n = hash(key);\n  auto first = buckets_[n];\n  if (first)\n  {\n    if (is_equal(value_traits::get_key(first->value), key))\n    {\n      buckets_[n] = first->next;\n      destroy_node(first);\n      --size_;\n      return 1;\n    }\n    else\n    {\n      auto next = first->next;\n      while (next)\n      {\n        if (is_equal(value_traits::get_key(next->value), key))\n        {\n          first->next = next->next;\n          destroy_node(next);\n          --size_;\n          return 1;\n        }\n        first = next;\n        next = first->next;\n      }\n    }\n  }\n  return 0;\n}\n\n// 清空 hashtable\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nclear()\n{\n  if (size_ != 0)\n  {\n    for (size_type i = 0; i < bucket_size_; ++i)\n    {\n      node_ptr cur = buckets_[i];\n      while (cur != nullptr)\n      {\n        node_ptr next = cur->next;\n        destroy_node(cur);\n        cur = next;\n      }\n      buckets_[i] = nullptr;\n    }\n    size_ = 0;\n  }\n}\n\n// 在某个 bucket 节点的个数\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::size_type\nhashtable<T, Hash, KeyEqual>::\nbucket_size(size_type n) const noexcept\n{\n  size_type result = 0;\n  for (auto cur = buckets_[n]; cur; cur = cur->next)\n  {\n    ++result;\n  }\n  return result;\n}\n\n// 重新对元素进行一遍哈希，插入到新的位置\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nrehash(size_type count)\n{\n  auto n = ht_next_prime(count);\n  if (n > bucket_size_)\n  {\n    replace_bucket(n);\n  }\n  else\n  {\n    if ((float)size_ / (float)n < max_load_factor() - 0.25f &&\n        (float)n < (float)bucket_size_ * 0.75)  // worth rehash\n    {\n      replace_bucket(n);\n    }\n  }\n}\n\n// 查找键值为 key 的节点，返回其迭代器\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::iterator\nhashtable<T, Hash, KeyEqual>::\nfind(const key_type& key)\n{\n  const auto n = hash(key);\n  node_ptr first = buckets_[n];\n  for (; first && !is_equal(value_traits::get_key(first->value), key); first = first->next) {}\n  return iterator(first, this);\n}\n\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::const_iterator\nhashtable<T, Hash, KeyEqual>::\nfind(const key_type& key) const\n{\n  const auto n = hash(key);\n  node_ptr first = buckets_[n];\n  for (; first && !is_equal(value_traits::get_key(first->value), key); first = first->next) {}\n  return M_cit(first);\n}\n\n// 查找键值为 key 出现的次数\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::size_type\nhashtable<T, Hash, KeyEqual>::\ncount(const key_type& key) const\n{\n  const auto n = hash(key);\n  size_type result = 0;\n  for (node_ptr cur = buckets_[n]; cur; cur = cur->next)\n  {\n    if (is_equal(value_traits::get_key(cur->value), key))\n      ++result;\n  }\n  return result;\n}\n\n// 查找与键值 key 相等的区间，返回一个 pair，指向相等区间的首尾\ntemplate <class T, class Hash, class KeyEqual>\npair<typename hashtable<T, Hash, KeyEqual>::iterator,\n  typename hashtable<T, Hash, KeyEqual>::iterator>\nhashtable<T, Hash, KeyEqual>::\nequal_range_multi(const key_type& key)\n{\n  const auto n = hash(key);\n  for (node_ptr first = buckets_[n]; first; first = first->next)\n  {\n    if (is_equal(value_traits::get_key(first->value), key))\n    { // 如果出现相等的键值\n      for (node_ptr second = first->next; second; second = second->next)\n      {\n        if (!is_equal(value_traits::get_key(second->value), key))\n          return mystl::make_pair(iterator(first, this), iterator(second, this));\n      }\n      for (auto m = n + 1; m < bucket_size_; ++m)\n      { // 整个链表都相等，查找下一个链表出现的位置\n        if (buckets_[m])\n          return mystl::make_pair(iterator(first, this), iterator(buckets_[m], this));\n      }\n      return mystl::make_pair(iterator(first, this), end());\n    }\n  }\n  return mystl::make_pair(end(), end());\n}\n\ntemplate <class T, class Hash, class KeyEqual>\npair<typename hashtable<T, Hash, KeyEqual>::const_iterator,\n  typename hashtable<T, Hash, KeyEqual>::const_iterator>\nhashtable<T, Hash, KeyEqual>::\nequal_range_multi(const key_type& key) const\n{\n  const auto n = hash(key);\n  for (node_ptr first = buckets_[n]; first; first = first->next)\n  {\n    if (is_equal(value_traits::get_key(first->value), key))\n    {\n      for (node_ptr second = first->next; second; second = second->next)\n      {\n        if (!is_equal(value_traits::get_key(second->value), key))\n          return mystl::make_pair(M_cit(first), M_cit(second));\n      }\n      for (auto m = n + 1; m < bucket_size_; ++m)\n      { // 整个链表都相等，查找下一个链表出现的位置\n        if (buckets_[m])\n          return mystl::make_pair(M_cit(first), M_cit(buckets_[m]));\n      }\n      return mystl::make_pair(M_cit(first), cend());\n    }\n  }\n  return mystl::make_pair(cend(), cend());\n}\n\ntemplate <class T, class Hash, class KeyEqual>\npair<typename hashtable<T, Hash, KeyEqual>::iterator,\n  typename hashtable<T, Hash, KeyEqual>::iterator>\nhashtable<T, Hash, KeyEqual>::\nequal_range_unique(const key_type& key)\n{\n  const auto n = hash(key);\n  for (node_ptr first = buckets_[n]; first; first = first->next)\n  {\n    if (is_equal(value_traits::get_key(first->value), key))\n    {\n      if (first->next)\n        return mystl::make_pair(iterator(first, this), iterator(first->next, this));\n      for (auto m = n + 1; m < bucket_size_; ++m)\n      { // 整个链表都相等，查找下一个链表出现的位置\n        if (buckets_[m])\n          return mystl::make_pair(iterator(first, this), iterator(buckets_[m], this));\n      }\n      return mystl::make_pair(iterator(first, this), end());\n    }\n  }\n  return mystl::make_pair(end(), end());\n}\n\ntemplate <class T, class Hash, class KeyEqual>\npair<typename hashtable<T, Hash, KeyEqual>::const_iterator,\n  typename hashtable<T, Hash, KeyEqual>::const_iterator>\nhashtable<T, Hash, KeyEqual>::\nequal_range_unique(const key_type& key) const\n{\n  const auto n = hash(key);\n  for (node_ptr first = buckets_[n]; first; first = first->next)\n  {\n    if (is_equal(value_traits::get_key(first->value), key))\n    {\n      if (first->next)\n        return mystl::make_pair(M_cit(first), M_cit(first->next));\n      for (auto m = n + 1; m < bucket_size_; ++m)\n      { // 整个链表都相等，查找下一个链表出现的位置\n        if (buckets_[m])\n          return mystl::make_pair(M_cit(first), M_cit(buckets_[m]));\n      }\n      return mystl::make_pair(M_cit(first), cend());\n    }\n  }\n  return mystl::make_pair(cend(), cend());\n}\n\n// 交换 hashtable\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nswap(hashtable& rhs) noexcept\n{\n  if (this != &rhs)\n  {\n    buckets_.swap(rhs.buckets_);\n    mystl::swap(bucket_size_, rhs.bucket_size_);\n    mystl::swap(size_, rhs.size_);\n    mystl::swap(mlf_, rhs.mlf_);\n    mystl::swap(hash_, rhs.hash_);\n    mystl::swap(equal_, rhs.equal_);\n  }\n}\n\n/****************************************************************************************/\n// helper function\n\n// init 函数\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\ninit(size_type n)\n{\n  const auto bucket_nums = next_size(n);\n  try\n  {\n    buckets_.reserve(bucket_nums);\n    buckets_.assign(bucket_nums, nullptr);\n  }\n  catch (...)\n  {\n    bucket_size_ = 0;\n    size_ = 0;\n    throw;\n  }\n  bucket_size_ = buckets_.size();\n}\n\n// copy_init 函数\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\ncopy_init(const hashtable& ht)\n{\n  bucket_size_ = 0;\n  buckets_.reserve(ht.bucket_size_);\n  buckets_.assign(ht.bucket_size_, nullptr);\n  try\n  {\n    for (size_type i = 0; i < ht.bucket_size_; ++i)\n    {\n      node_ptr cur = ht.buckets_[i];\n      if (cur)\n      { // 如果某 bucket 存在链表\n        auto copy = create_node(cur->value);\n        buckets_[i] = copy;\n        for (auto next = cur->next; next; cur = next, next = cur->next)\n        {  //复制链表\n          copy->next = create_node(next->value);\n          copy = copy->next;\n        }\n        copy->next = nullptr;\n      }\n    }\n    bucket_size_ = ht.bucket_size_;\n    mlf_ = ht.mlf_;\n    size_ = ht.size_;\n  }\n  catch (...)\n  {\n    clear();\n  }\n}\n\n// create_node 函数\ntemplate <class T, class Hash, class KeyEqual>\ntemplate <class ...Args>\ntypename hashtable<T, Hash, KeyEqual>::node_ptr\nhashtable<T, Hash, KeyEqual>::\ncreate_node(Args&& ...args)\n{\n  node_ptr tmp = node_allocator::allocate(1);\n  try\n  {\n    data_allocator::construct(mystl::address_of(tmp->value), mystl::forward<Args>(args)...);\n    tmp->next = nullptr;\n  }\n  catch (...)\n  {\n    node_allocator::deallocate(tmp);\n    throw;\n  }\n  return tmp;\n}\n\n// destroy_node 函数\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\ndestroy_node(node_ptr node)\n{\n  data_allocator::destroy(mystl::address_of(node->value));\n  node_allocator::deallocate(node);\n  node = nullptr;\n}\n\n// next_size 函数\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::size_type\nhashtable<T, Hash, KeyEqual>::next_size(size_type n) const\n{\n  return ht_next_prime(n);\n}\n\n// hash 函数\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::size_type\nhashtable<T, Hash, KeyEqual>::\nhash(const key_type& key, size_type n) const\n{\n  return hash_(key) % n;\n}\n\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::size_type\nhashtable<T, Hash, KeyEqual>::\nhash(const key_type& key) const\n{\n  return hash_(key) % bucket_size_;\n}\n\n// rehash_if_need 函数\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nrehash_if_need(size_type n)\n{\n  if (static_cast<float>(size_ + n) > (float)bucket_size_ * max_load_factor())\n    rehash(size_ + n);\n}\n\n// copy_insert\ntemplate <class T, class Hash, class KeyEqual>\ntemplate <class InputIter>\nvoid hashtable<T, Hash, KeyEqual>::\ncopy_insert_multi(InputIter first, InputIter last, mystl::input_iterator_tag)\n{\n  rehash_if_need(mystl::distance(first, last));\n  for (; first != last; ++first)\n    insert_multi_noresize(*first);\n}\n\ntemplate <class T, class Hash, class KeyEqual>\ntemplate <class ForwardIter>\nvoid hashtable<T, Hash, KeyEqual>::\ncopy_insert_multi(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag)\n{\n  size_type n = mystl::distance(first, last);\n  rehash_if_need(n);\n  for (; n > 0; --n, ++first)\n    insert_multi_noresize(*first);\n}\n\ntemplate <class T, class Hash, class KeyEqual>\ntemplate <class InputIter>\nvoid hashtable<T, Hash, KeyEqual>::\ncopy_insert_unique(InputIter first, InputIter last, mystl::input_iterator_tag)\n{\n  rehash_if_need(mystl::distance(first, last));\n  for (; first != last; ++first)\n    insert_unique_noresize(*first);\n}\n\ntemplate <class T, class Hash, class KeyEqual>\ntemplate <class ForwardIter>\nvoid hashtable<T, Hash, KeyEqual>::\ncopy_insert_unique(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag)\n{\n  size_type n = mystl::distance(first, last);\n  rehash_if_need(n);\n  for (; n > 0; --n, ++first)\n    insert_unique_noresize(*first);\n}\n\n// insert_node 函数\ntemplate <class T, class Hash, class KeyEqual>\ntypename hashtable<T, Hash, KeyEqual>::iterator\nhashtable<T, Hash, KeyEqual>::\ninsert_node_multi(node_ptr np)\n{\n  const auto n = hash(value_traits::get_key(np->value));\n  auto cur = buckets_[n];\n  if (cur == nullptr)\n  {\n    buckets_[n] = np;\n    ++size_;\n    return iterator(np, this);\n  }\n  for (; cur; cur = cur->next)\n  {\n    if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(np->value)))\n    {\n      np->next = cur->next;\n      cur->next = np;\n      ++size_;\n      return iterator(np, this);\n    }\n  }\n  np->next = buckets_[n];\n  buckets_[n] = np;\n  ++size_;\n  return iterator(np, this);\n}\n\n// insert_node_unique 函数\ntemplate <class T, class Hash, class KeyEqual>\npair<typename hashtable<T, Hash, KeyEqual>::iterator, bool>\nhashtable<T, Hash, KeyEqual>::\ninsert_node_unique(node_ptr np)\n{\n  const auto n = hash(value_traits::get_key(np->value));\n  auto cur = buckets_[n];\n  if (cur == nullptr)\n  {\n    buckets_[n] = np;\n    ++size_;\n    return mystl::make_pair(iterator(np, this), true);\n  }\n  for (; cur; cur = cur->next)\n  {\n    if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(np->value)))\n    {\n      return mystl::make_pair(iterator(cur, this), false);\n    }\n  }\n  np->next = buckets_[n];\n  buckets_[n] = np;\n  ++size_;\n  return mystl::make_pair(iterator(np, this), true);\n}\n\n// replace_bucket 函数\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nreplace_bucket(size_type bucket_count)\n{\n  bucket_type bucket(bucket_count);\n  if (size_ != 0)\n  {\n    for (size_type i = 0; i < bucket_size_; ++i)\n    {\n      for (auto first = buckets_[i]; first; first = first->next)\n      {\n        auto tmp = create_node(first->value);\n        const auto n = hash(value_traits::get_key(first->value), bucket_count);\n        auto f = bucket[n];\n        bool is_inserted = false;\n        for (auto cur = f; cur; cur = cur->next)\n        {\n          if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(first->value)))\n          {\n            tmp->next = cur->next;\n            cur->next = tmp;\n            is_inserted = true;\n            break;\n          }\n        }\n        if (!is_inserted)\n        {\n          tmp->next = f;\n          bucket[n] = tmp;\n        }\n      }\n    }\n  }\n  buckets_.swap(bucket);\n  bucket_size_ = buckets_.size();\n}\n\n// erase_bucket 函数\n// 在第 n 个 bucket 内，删除 [first, last) 的节点\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nerase_bucket(size_type n, node_ptr first, node_ptr last)\n{\n  auto cur = buckets_[n];\n  if (cur == first)\n  {\n    erase_bucket(n, last);\n  }\n  else\n  {\n    node_ptr next = cur->next;\n    for (; next != first; cur = next, next = cur->next) {}\n    while (next != last)\n    {\n      cur->next = next->next;\n      destroy_node(next);\n      next = cur->next;\n      --size_;\n    }\n  }\n}\n\n// erase_bucket 函数\n// 在第 n 个 bucket 内，删除 [buckets_[n], last) 的节点\ntemplate <class T, class Hash, class KeyEqual>\nvoid hashtable<T, Hash, KeyEqual>::\nerase_bucket(size_type n, node_ptr last)\n{\n  auto cur = buckets_[n];\n  while (cur != last)\n  {\n    auto next = cur->next;\n    destroy_node(cur);\n    cur = next;\n    --size_;\n  }\n  buckets_[n] = last;\n}\n\n// equal_to 函数\ntemplate <class T, class Hash, class KeyEqual>\nbool hashtable<T, Hash, KeyEqual>::equal_to_multi(const hashtable& other)\n{\n  if (size_ != other.size_)\n    return false;\n  for (auto f = begin(), l = end(); f != l;)\n  {\n    auto p1 = equal_range_multi(value_traits::get_key(*f));\n    auto p2 = other.equal_range_multi(value_traits::get_key(*f));\n    if (mystl::distance(p1.first, p1.last) != mystl::distance(p2.first, p2.last) ||\n        !mystl::is_permutation(p1.first, p2.last, p2.first, p2.last))\n      return false;\n    f = p1.last;\n  }\n  return true;\n}\n\ntemplate <class T, class Hash, class KeyEqual>\nbool hashtable<T, Hash, KeyEqual>::equal_to_unique(const hashtable& other)\n{\n  if (size_ != other.size_)\n    return false;\n  for (auto f = begin(), l = end(); f != l; ++f)\n  {\n    auto res = other.find(value_traits::get_key(*f));\n    if (res.node == nullptr || *res != *f)\n      return false;\n  }\n  return true;\n}\n\n// 重载 mystl 的 swap\ntemplate <class T, class Hash, class KeyEqual>\nvoid swap(hashtable<T, Hash, KeyEqual>& lhs,\n          hashtable<T, Hash, KeyEqual>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_HASHTABLE_H_\n\n"
  },
  {
    "path": "MyTinySTL/heap_algo.h",
    "content": "﻿#ifndef MYTINYSTL_HEAP_ALGO_H_\n#define MYTINYSTL_HEAP_ALGO_H_\n\n// 这个头文件包含 heap 的四个算法 : push_heap, pop_heap, sort_heap, make_heap\n\n#include \"iterator.h\"\n\nnamespace mystl\n{\n\n/*****************************************************************************************/\n// push_heap\n// 该函数接受两个迭代器，表示一个 heap 容器的首尾，并且新元素已经插入到底部容器的最尾端，调整 heap\n/*****************************************************************************************/\ntemplate <class RandomIter, class Distance, class T>\nvoid push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, T value)\n{\n  auto parent = (holeIndex - 1) / 2;\n  while (holeIndex > topIndex && *(first + parent) < value)\n  {\n    // 使用 operator<，所以 heap 为 max-heap\n    *(first + holeIndex) = *(first + parent);\n    holeIndex = parent;\n    parent = (holeIndex - 1) / 2;\n  }\n  *(first + holeIndex) = value;\n}\n\ntemplate <class RandomIter, class Distance>\nvoid push_heap_d(RandomIter first, RandomIter last, Distance*)\n{\n  mystl::push_heap_aux(first, (last - first) - 1, static_cast<Distance>(0), *(last - 1));\n}\n\ntemplate <class RandomIter>\nvoid push_heap(RandomIter first, RandomIter last)\n{ // 新元素应该已置于底部容器的最尾端\n  mystl::push_heap_d(first, last, distance_type(first));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class RandomIter, class Distance, class T, class Compared>\nvoid push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, T value,\n                   Compared comp)\n{\n  auto parent = (holeIndex - 1) / 2;\n  while (holeIndex > topIndex && comp(*(first + parent), value))\n  {\n    *(first + holeIndex) = *(first + parent);\n    holeIndex = parent;\n    parent = (holeIndex - 1) / 2;\n  }\n  *(first + holeIndex) = value;\n}\n\ntemplate <class RandomIter, class Compared, class Distance>\nvoid push_heap_d(RandomIter first, RandomIter last, Distance*, Compared comp)\n{\n  mystl::push_heap_aux(first, (last - first) - 1, static_cast<Distance>(0),\n                       *(last - 1), comp);\n}\n\ntemplate <class RandomIter, class Compared>\nvoid push_heap(RandomIter first, RandomIter last, Compared comp)\n{\n  mystl::push_heap_d(first, last, distance_type(first), comp);\n}\n\n/*****************************************************************************************/\n// pop_heap\n// 该函数接受两个迭代器，表示 heap 容器的首尾，将 heap 的根节点取出放到容器尾部，调整 heap\n/*****************************************************************************************/\ntemplate <class RandomIter, class T, class Distance>\nvoid adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value)\n{\n  // 先进行下溯(percolate down)过程\n  auto topIndex = holeIndex;\n  auto rchild = 2 * holeIndex + 2;\n  while (rchild < len)\n  {\n    if (*(first + rchild) < *(first + rchild - 1))\n      --rchild;\n    *(first + holeIndex) = *(first + rchild);\n    holeIndex = rchild;\n    rchild = 2 * (rchild + 1);\n  }\n  if (rchild == len)\n  {  // 如果没有右子节点\n    *(first + holeIndex) = *(first + (rchild - 1));\n    holeIndex = rchild - 1;\n  }\n  // 再执行一次上溯(percolate up)过程\n  mystl::push_heap_aux(first, holeIndex, topIndex, value);\n}\n\ntemplate <class RandomIter, class T, class Distance>\nvoid pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, T value,\n                  Distance*)\n{\n  // 先将首值调至尾节点，然后调整[first, last - 1)使之重新成为一个 max-heap\n  *result = *first;\n  mystl::adjust_heap(first, static_cast<Distance>(0), last - first, value);\n}\n\ntemplate <class RandomIter>\nvoid pop_heap(RandomIter first, RandomIter last)\n{\n  mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), distance_type(first));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class RandomIter, class T, class Distance, class Compared>\nvoid adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value,\n                 Compared comp)\n{\n  // 先进行下溯(percolate down)过程\n  auto topIndex = holeIndex;\n  auto rchild = 2 * holeIndex + 2;\n  while (rchild < len)\n  {\n    if (comp(*(first + rchild), *(first + rchild - 1)))  --rchild;\n    *(first + holeIndex) = *(first + rchild);\n    holeIndex = rchild;\n    rchild = 2 * (rchild + 1);\n  }\n  if (rchild == len)\n  {\n    *(first + holeIndex) = *(first + (rchild - 1));\n    holeIndex = rchild - 1;\n  }\n  // 再执行一次上溯(percolate up)过程\n  mystl::push_heap_aux(first, holeIndex, topIndex, value, comp);\n}\n\ntemplate <class RandomIter, class T, class Distance, class Compared>\nvoid pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, \n                  T value, Distance*, Compared comp)\n{\n  *result = *first;  // 先将尾指设置成首值，即尾指为欲求结果\n  mystl::adjust_heap(first, static_cast<Distance>(0), last - first, value, comp);\n}\n\ntemplate <class RandomIter, class Compared>\nvoid pop_heap(RandomIter first, RandomIter last, Compared comp)\n{\n  mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1),\n                      distance_type(first), comp);\n}\n\n/*****************************************************************************************/\n// sort_heap\n// 该函数接受两个迭代器，表示 heap 容器的首尾，不断执行 pop_heap 操作，直到首尾最多相差1\n/*****************************************************************************************/\ntemplate <class RandomIter>\nvoid sort_heap(RandomIter first, RandomIter last)\n{\n  // 每执行一次 pop_heap，最大的元素都被放到尾部，直到容器最多只有一个元素，完成排序\n  while (last - first > 1)\n  {\n    mystl::pop_heap(first, last--);\n  }\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class RandomIter, class Compared>\nvoid sort_heap(RandomIter first, RandomIter last, Compared comp)\n{\n  while (last - first > 1)\n  {\n    mystl::pop_heap(first, last--, comp);\n  }\n}\n\n/*****************************************************************************************/\n// make_heap\n// 该函数接受两个迭代器，表示 heap 容器的首尾，把容器内的数据变为一个 heap\n/*****************************************************************************************/\ntemplate <class RandomIter, class Distance>\nvoid make_heap_aux(RandomIter first, RandomIter last, Distance*)\n{\n  if (last - first < 2)\n    return;\n  auto len = last - first;\n  auto holeIndex = (len - 2) / 2;\n  while (true)\n  {\n    // 重排以 holeIndex 为首的子树\n    mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex));\n    if (holeIndex == 0)\n      return;\n    holeIndex--;\n  }\n}\n\ntemplate <class RandomIter>\nvoid make_heap(RandomIter first, RandomIter last)\n{\n  mystl::make_heap_aux(first, last, distance_type(first));;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class RandomIter, class Distance, class Compared>\nvoid make_heap_aux(RandomIter first, RandomIter last, Distance*, Compared comp)\n{\n  if (last - first < 2)\n    return;\n  auto len = last - first;\n  auto holeIndex = (len - 2) / 2;\n  while (true)\n  {\n    // 重排以 holeIndex 为首的子树\n    mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex), comp);\n    if (holeIndex == 0)\n      return;\n    holeIndex--;\n  }\n}\n\ntemplate <class RandomIter, class Compared>\nvoid make_heap(RandomIter first, RandomIter last, Compared comp)\n{\n  mystl::make_heap_aux(first, last, distance_type(first), comp);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_HEAP_ALGO_H_\n\n"
  },
  {
    "path": "MyTinySTL/iterator.h",
    "content": "﻿#ifndef MYTINYSTL_ITERATOR_H_\n#define MYTINYSTL_ITERATOR_H_\n\n// 这个头文件用于迭代器设计，包含了一些模板结构体与全局函数，\n\n#include <cstddef>\n\n#include \"type_traits.h\"\n\nnamespace mystl\n{\n\n// 五种迭代器类型\nstruct input_iterator_tag {};\nstruct output_iterator_tag {};\nstruct forward_iterator_tag : public input_iterator_tag {};\nstruct bidirectional_iterator_tag : public forward_iterator_tag {};\nstruct random_access_iterator_tag : public bidirectional_iterator_tag {};\n\n// iterator 模板\ntemplate <class Category, class T, class Distance = ptrdiff_t,\n  class Pointer = T*, class Reference = T&>\n  struct iterator\n{\n  typedef Category                             iterator_category;\n  typedef T                                    value_type;\n  typedef Pointer                              pointer;\n  typedef Reference                            reference;\n  typedef Distance                             difference_type;\n};\n\n// iterator traits\n\ntemplate <class T>\nstruct has_iterator_cat\n{\nprivate:\n  struct two { char a; char b; };\n  template <class U> static two test(...);\n  template <class U> static char test(typename U::iterator_category* = 0);\npublic:\n  static const bool value = sizeof(test<T>(0)) == sizeof(char);\n};\n\ntemplate <class Iterator, bool>\nstruct iterator_traits_impl {};\n\ntemplate <class Iterator>\nstruct iterator_traits_impl<Iterator, true>\n{\n  typedef typename Iterator::iterator_category iterator_category;\n  typedef typename Iterator::value_type        value_type;\n  typedef typename Iterator::pointer           pointer;\n  typedef typename Iterator::reference         reference;\n  typedef typename Iterator::difference_type   difference_type;\n};\n\ntemplate <class Iterator, bool>\nstruct iterator_traits_helper {};\n\ntemplate <class Iterator>\nstruct iterator_traits_helper<Iterator, true>\n  : public iterator_traits_impl<Iterator,\n  std::is_convertible<typename Iterator::iterator_category, input_iterator_tag>::value ||\n  std::is_convertible<typename Iterator::iterator_category, output_iterator_tag>::value>\n{\n};\n\n// 萃取迭代器的特性\ntemplate <class Iterator>\nstruct iterator_traits \n  : public iterator_traits_helper<Iterator, has_iterator_cat<Iterator>::value> {};\n\n// 针对原生指针的偏特化版本\ntemplate <class T>\nstruct iterator_traits<T*>\n{\n  typedef random_access_iterator_tag           iterator_category;\n  typedef T                                    value_type;\n  typedef T*                                   pointer;\n  typedef T&                                   reference;\n  typedef ptrdiff_t                            difference_type;\n};\n\ntemplate <class T>\nstruct iterator_traits<const T*>\n{\n  typedef random_access_iterator_tag           iterator_category;\n  typedef T                                    value_type;\n  typedef const T*                             pointer;\n  typedef const T&                             reference;\n  typedef ptrdiff_t                            difference_type;\n};\n\ntemplate <class T, class U, bool = has_iterator_cat<iterator_traits<T>>::value>\nstruct has_iterator_cat_of\n  : public m_bool_constant<std::is_convertible<\n  typename iterator_traits<T>::iterator_category, U>::value>\n{\n};\n\n// 萃取某种迭代器\ntemplate <class T, class U>\nstruct has_iterator_cat_of<T, U, false> : public m_false_type {};\n\ntemplate <class Iter>\nstruct is_exactly_input_iterator : public m_bool_constant<has_iterator_cat_of<Iter, input_iterator_tag>::value && \n    !has_iterator_cat_of<Iter, forward_iterator_tag>::value> {};\n\ntemplate <class Iter>\nstruct is_input_iterator : public has_iterator_cat_of<Iter, input_iterator_tag> {};\n\ntemplate <class Iter>\nstruct is_output_iterator : public has_iterator_cat_of<Iter, output_iterator_tag> {};\n\ntemplate <class Iter>\nstruct is_forward_iterator : public has_iterator_cat_of<Iter, forward_iterator_tag> {};\n\ntemplate <class Iter>\nstruct is_bidirectional_iterator : public has_iterator_cat_of<Iter, bidirectional_iterator_tag> {};\n\ntemplate <class Iter>\nstruct is_random_access_iterator : public has_iterator_cat_of<Iter, random_access_iterator_tag> {};\n\ntemplate <class Iterator>\nstruct is_iterator :\n  public m_bool_constant<is_input_iterator<Iterator>::value ||\n    is_output_iterator<Iterator>::value>\n{\n};\n\n// 萃取某个迭代器的 category\ntemplate <class Iterator>\ntypename iterator_traits<Iterator>::iterator_category\niterator_category(const Iterator&)\n{\n  typedef typename iterator_traits<Iterator>::iterator_category Category;\n  return Category();\n}\n\n// 萃取某个迭代器的 distance_type\ntemplate <class Iterator>\ntypename iterator_traits<Iterator>::difference_type*\ndistance_type(const Iterator&)\n{\n  return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);\n}\n\n// 萃取某个迭代器的 value_type\ntemplate <class Iterator>\ntypename iterator_traits<Iterator>::value_type*\nvalue_type(const Iterator&)\n{\n  return static_cast<typename iterator_traits<Iterator>::value_type*>(0);\n}\n\n// 以下函数用于计算迭代器间的距离\n\n// distance 的 input_iterator_tag 的版本\ntemplate <class InputIterator>\ntypename iterator_traits<InputIterator>::difference_type\ndistance_dispatch(InputIterator first, InputIterator last, input_iterator_tag)\n{\n  typename iterator_traits<InputIterator>::difference_type n = 0;\n  while (first != last)\n  {\n    ++first;\n    ++n;\n  }\n  return n;\n}\n\n// distance 的 random_access_iterator_tag 的版本\ntemplate <class RandomIter>\ntypename iterator_traits<RandomIter>::difference_type\ndistance_dispatch(RandomIter first, RandomIter last,\n                  random_access_iterator_tag)\n{\n  return last - first;\n}\n\ntemplate <class InputIterator>\ntypename iterator_traits<InputIterator>::difference_type\ndistance(InputIterator first, InputIterator last)\n{\n  return distance_dispatch(first, last, iterator_category(first));\n}\n\n// 以下函数用于让迭代器前进 n 个距离\n\n// advance 的 input_iterator_tag 的版本\ntemplate <class InputIterator, class Distance>\nvoid advance_dispatch(InputIterator& i, Distance n, input_iterator_tag)\n{\n  while (n--) \n    ++i;\n}\n\n// advance 的 bidirectional_iterator_tag 的版本\ntemplate <class BidirectionalIterator, class Distance>\nvoid advance_dispatch(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag)\n{\n  if (n >= 0)\n    while (n--)  ++i;\n  else\n    while (n++)  --i;\n}\n\n// advance 的 random_access_iterator_tag 的版本\ntemplate <class RandomIter, class Distance>\nvoid advance_dispatch(RandomIter& i, Distance n, random_access_iterator_tag)\n{\n  i += n;\n}\n\ntemplate <class InputIterator, class Distance>\nvoid advance(InputIterator& i, Distance n)\n{\n  advance_dispatch(i, n, iterator_category(i));\n}\n\n/*****************************************************************************************/\n\n// 模板类 : reverse_iterator\n// 代表反向迭代器，使前进为后退，后退为前进\ntemplate <class Iterator>\nclass reverse_iterator\n{\nprivate:\n  Iterator current;  // 记录对应的正向迭代器\n\npublic:\n  // 反向迭代器的五种相应型别\n  typedef typename iterator_traits<Iterator>::iterator_category iterator_category;\n  typedef typename iterator_traits<Iterator>::value_type        value_type;\n  typedef typename iterator_traits<Iterator>::difference_type   difference_type;\n  typedef typename iterator_traits<Iterator>::pointer           pointer;\n  typedef typename iterator_traits<Iterator>::reference         reference;\n\n  typedef Iterator                                              iterator_type;\n  typedef reverse_iterator<Iterator>                            self;\n\npublic:\n  // 构造函数\n  reverse_iterator() {}\n  explicit reverse_iterator(iterator_type i) :current(i) {}\n  reverse_iterator(const self& rhs) :current(rhs.current) {}\n\npublic:\n  // 取出对应的正向迭代器\n  iterator_type base() const \n  { return current; }\n\n  // 重载操作符\n  reference operator*() const\n  { // 实际对应正向迭代器的前一个位置\n    auto tmp = current;\n    return *--tmp;\n  }\n  pointer operator->() const\n  {\n    return &(operator*());\n  }\n\n  // 前进(++)变为后退(--)\n  self& operator++()\n  {\n    --current;\n    return *this;\n  }\n  self operator++(int)\n  {\n    self tmp = *this;\n    --current;\n    return tmp;\n  }\n  // 后退(--)变为前进(++)\n  self& operator--()\n  {\n    ++current;\n    return *this;\n  }\n  self operator--(int)\n  {\n    self tmp = *this;\n    ++current;\n    return tmp;\n  }\n\n  self& operator+=(difference_type n)\n  {\n    current -= n;\n    return *this;\n  }\n  self operator+(difference_type n) const\n  {\n    return self(current - n);\n  }\n  self& operator-=(difference_type n)\n  {\n    current += n;\n    return *this;\n  }\n  self operator-(difference_type n) const\n  {\n    return self(current + n);\n  }\n\n  reference operator[](difference_type n) const\n  {\n    return *(*this + n);\n  }\n};\n\n// 重载 operator-\ntemplate <class Iterator>\ntypename reverse_iterator<Iterator>::difference_type\noperator-(const reverse_iterator<Iterator>& lhs,\n          const reverse_iterator<Iterator>& rhs)\n{\n  return rhs.base() - lhs.base();\n}\n\n// 重载比较操作符\ntemplate <class Iterator>\nbool operator==(const reverse_iterator<Iterator>& lhs,\n                const reverse_iterator<Iterator>& rhs)\n{\n  return lhs.base() == rhs.base();\n}\n\ntemplate <class Iterator>\nbool operator<(const reverse_iterator<Iterator>& lhs,\n  const reverse_iterator<Iterator>& rhs)\n{\n  return rhs.base() < lhs.base();\n}\n\ntemplate <class Iterator>\nbool operator!=(const reverse_iterator<Iterator>& lhs,\n                const reverse_iterator<Iterator>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class Iterator>\nbool operator>(const reverse_iterator<Iterator>& lhs,\n               const reverse_iterator<Iterator>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class Iterator>\nbool operator<=(const reverse_iterator<Iterator>& lhs,\n                const reverse_iterator<Iterator>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class Iterator>\nbool operator>=(const reverse_iterator<Iterator>& lhs,\n                const reverse_iterator<Iterator>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n} // namespace mystl\n\n#endif // !MYTINYSTL_ITERATOR_H_\n\n"
  },
  {
    "path": "MyTinySTL/list.h",
    "content": "﻿#ifndef MYTINYSTL_LIST_H_\n#define MYTINYSTL_LIST_H_\n\n// 这个头文件包含了一个模板类 list\n// list : 双向链表\n\n// notes:\n//\n// 异常保证：\n// mystl::list<T> 满足基本异常保证，部分函数无异常保证，并对以下等函数做强异常安全保证：\n//   * emplace_front\n//   * emplace_back\n//   * emplace\n//   * push_front\n//   * push_back\n//   * insert\n\n#include <initializer_list>\n\n#include \"iterator.h\"\n#include \"memory.h\"\n#include \"functional.h\"\n#include \"util.h\"\n#include \"exceptdef.h\"\n\nnamespace mystl\n{\n\ntemplate <class T> struct list_node_base;\ntemplate <class T> struct list_node;\n\ntemplate <class T>\nstruct node_traits\n{\n  typedef list_node_base<T>* base_ptr;\n  typedef list_node<T>*      node_ptr;\n};\n\n// list 的节点结构\n\ntemplate <class T>\nstruct list_node_base\n{\n  typedef typename node_traits<T>::base_ptr base_ptr;\n  typedef typename node_traits<T>::node_ptr node_ptr;\n\n  base_ptr prev;  // 前一节点\n  base_ptr next;  // 下一节点\n\n  list_node_base() = default;\n\n  node_ptr as_node()\n  {\n    return static_cast<node_ptr>(self());\n  }\n\n  void unlink()\n  {\n    prev = next = self();\n  }\n\n  base_ptr self()\n  {\n    return static_cast<base_ptr>(&*this);\n  }\n};\n\ntemplate <class T>\nstruct list_node : public list_node_base<T>\n{\n  typedef typename node_traits<T>::base_ptr base_ptr;\n  typedef typename node_traits<T>::node_ptr node_ptr;\n\n  T value;  // 数据域\n\n  list_node() = default;\n  list_node(const T& v)\n    :value(v)\n  {\n  }\n  list_node(T&& v)\n    :value(mystl::move(v))\n  {\n  }\n\n  base_ptr as_base()\n  {\n    return static_cast<base_ptr>(&*this);\n  }\n  node_ptr self()\n  {\n    return static_cast<node_ptr>(&*this);\n  }\n};\n\n// list 的迭代器设计\ntemplate <class T>\nstruct list_iterator : public mystl::iterator<mystl::bidirectional_iterator_tag, T>\n{\n  typedef T                                 value_type;\n  typedef T*                                pointer;\n  typedef T&                                reference;\n  typedef typename node_traits<T>::base_ptr base_ptr;\n  typedef typename node_traits<T>::node_ptr node_ptr;\n  typedef list_iterator<T>                  self;\n\n  base_ptr node_;  // 指向当前节点\n\n  // 构造函数\n  list_iterator() = default;\n  list_iterator(base_ptr x)\n    :node_(x) {}\n  list_iterator(node_ptr x)\n    :node_(x->as_base()) {}\n  list_iterator(const list_iterator& rhs)\n    :node_(rhs.node_) {}\n\n  // 重载操作符\n  reference operator*()  const { return node_->as_node()->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  self& operator++()\n  {\n    MYSTL_DEBUG(node_ != nullptr);\n    node_ = node_->next;\n    return *this;\n  }\n  self operator++(int)\n  {\n    self tmp = *this;\n    ++*this;\n    return tmp;\n  }\n  self& operator--()\n  {\n    MYSTL_DEBUG(node_ != nullptr);\n    node_ = node_->prev;\n    return *this;\n  }\n  self operator--(int)\n  {\n    self tmp = *this;\n    --*this;\n    return tmp;\n  }\n\n  // 重载比较操作符\n  bool operator==(const self& rhs) const { return node_ == rhs.node_; }\n  bool operator!=(const self& rhs) const { return node_ != rhs.node_; }\n};\n\ntemplate <class T>\nstruct list_const_iterator : public iterator<bidirectional_iterator_tag, T>\n{\n  typedef T                                 value_type;\n  typedef const T*                          pointer;\n  typedef const T&                          reference;\n  typedef typename node_traits<T>::base_ptr base_ptr;\n  typedef typename node_traits<T>::node_ptr node_ptr;\n  typedef list_const_iterator<T>            self;\n\n  base_ptr node_;\n\n  list_const_iterator() = default;\n  list_const_iterator(base_ptr x)\n    :node_(x) {}\n  list_const_iterator(node_ptr x)\n    :node_(x->as_base()) {}\n  list_const_iterator(const list_iterator<T>& rhs)\n    :node_(rhs.node_) {}\n  list_const_iterator(const list_const_iterator& rhs)\n    :node_(rhs.node_) {}\n\n  reference operator*()  const { return node_->as_node()->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  self& operator++()\n  {\n    MYSTL_DEBUG(node_ != nullptr);\n    node_ = node_->next;\n    return *this;\n  }\n  self operator++(int)\n  {\n    self tmp = *this;\n    ++*this;\n    return tmp;\n  }\n  self& operator--()\n  {\n    MYSTL_DEBUG(node_ != nullptr);\n    node_ = node_->prev;\n    return *this;\n  }\n  self operator--(int)\n  {\n    self tmp = *this;\n    --*this;\n    return tmp;\n  }\n\n  // 重载比较操作符\n  bool operator==(const self& rhs) const { return node_ == rhs.node_; }\n  bool operator!=(const self& rhs) const { return node_ != rhs.node_; }\n};\n\n// 模板类: list\n// 模板参数 T 代表数据类型\ntemplate <class T>\nclass list\n{\npublic:\n  // list 的嵌套型别定义\n  typedef mystl::allocator<T>                      allocator_type;\n  typedef mystl::allocator<T>                      data_allocator;\n  typedef mystl::allocator<list_node_base<T>>      base_allocator;\n  typedef mystl::allocator<list_node<T>>           node_allocator;\n\n  typedef typename allocator_type::value_type      value_type;\n  typedef typename allocator_type::pointer         pointer;\n  typedef typename allocator_type::const_pointer   const_pointer;\n  typedef typename allocator_type::reference       reference;\n  typedef typename allocator_type::const_reference const_reference;\n  typedef typename allocator_type::size_type       size_type;\n  typedef typename allocator_type::difference_type difference_type;\n\n  typedef list_iterator<T>                         iterator;\n  typedef list_const_iterator<T>                   const_iterator;\n  typedef mystl::reverse_iterator<iterator>        reverse_iterator;\n  typedef mystl::reverse_iterator<const_iterator>  const_reverse_iterator;\n\n  typedef typename node_traits<T>::base_ptr        base_ptr;\n  typedef typename node_traits<T>::node_ptr        node_ptr;\n\n  allocator_type get_allocator() { return node_allocator(); }\n\nprivate:\n  base_ptr  node_;  // 指向末尾节点\n  size_type size_;  // 大小\n\npublic:\n  // 构造、复制、移动、析构函数\n  list() \n  { fill_init(0, value_type()); }\n\n  explicit list(size_type n) \n  { fill_init(n, value_type()); }\n\n  list(size_type n, const T& value)\n  { fill_init(n, value); }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  list(Iter first, Iter last)\n  { copy_init(first, last); }\n\n  list(std::initializer_list<T> ilist)\n  { copy_init(ilist.begin(), ilist.end()); }\n\n  list(const list& rhs)\n  { copy_init(rhs.cbegin(), rhs.cend()); }\n\n  list(list&& rhs) noexcept\n    :node_(rhs.node_), size_(rhs.size_)\n  {\n    rhs.node_ = nullptr;\n    rhs.size_ = 0;\n  }\n\n  list& operator=(const list& rhs)\n  {\n    if (this != &rhs)\n    {\n      assign(rhs.begin(), rhs.end());\n    }\n    return *this;\n  }\n\n  list& operator=(list&& rhs) noexcept\n  {\n    clear();\n    splice(end(), rhs);\n    return *this;\n  }\n\n  list& operator=(std::initializer_list<T> ilist)\n  {\n    list tmp(ilist.begin(), ilist.end());\n    swap(tmp);\n    return *this;\n  }\n\n  ~list()\n  {\n    if (node_)\n    {\n      clear();\n      base_allocator::deallocate(node_);\n      node_ = nullptr;\n      size_ = 0;\n    }\n  }\n\npublic:\n  // 迭代器相关操作\n  iterator               begin()         noexcept\n  { return node_->next; }\n  const_iterator         begin()   const noexcept\n  { return node_->next; }\n  iterator               end()           noexcept \n  { return node_; }\n  const_iterator         end()     const noexcept\n  { return node_; }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关操作\n  bool      empty()    const noexcept \n  { return node_->next == node_; }\n\n  size_type size()     const noexcept \n  { return size_; }\n\n  size_type max_size() const noexcept \n  { return static_cast<size_type>(-1); }\n\n  // 访问元素相关操作\n  reference       front() \n  { \n    MYSTL_DEBUG(!empty());\n    return *begin();\n  }\n\n  const_reference front() const \n  { \n    MYSTL_DEBUG(!empty()); \n    return *begin(); \n  }\n\n  reference       back() \n  { \n    MYSTL_DEBUG(!empty());\n    return *(--end());\n  }\n\n  const_reference back()  const \n  { \n    MYSTL_DEBUG(!empty()); \n    return *(--end());\n  }\n\n  // 调整容器相关操作\n\n  // assign\n\n  void     assign(size_type n, const value_type& value) \n  { fill_assign(n, value); }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  void     assign(Iter first, Iter last)\n  { copy_assign(first, last); }\n\n  void     assign(std::initializer_list<T> ilist)\n  { copy_assign(ilist.begin(), ilist.end()); }\n\n  // emplace_front / emplace_back / emplace\n\n  template <class ...Args>\n  void     emplace_front(Args&& ...args)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n    auto link_node = create_node(mystl::forward<Args>(args)...);\n    link_nodes_at_front(link_node->as_base(), link_node->as_base());\n    ++size_;\n  }\n\n  template <class ...Args>\n  void     emplace_back(Args&& ...args)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n    auto link_node = create_node(mystl::forward<Args>(args)...);\n    link_nodes_at_back(link_node->as_base(), link_node->as_base());\n    ++size_;\n  }\n\n  template <class ...Args>\n  iterator emplace(const_iterator pos, Args&& ...args)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n    auto link_node = create_node(mystl::forward<Args>(args)...);\n    link_nodes(pos.node_, link_node->as_base(), link_node->as_base());\n    ++size_;\n    return iterator(link_node);\n  }\n\n  // insert\n\n  iterator insert(const_iterator pos, const value_type& value)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n    auto link_node = create_node(value);\n    ++size_;\n    return link_iter_node(pos, link_node->as_base());\n  }\n\n  iterator insert(const_iterator pos, value_type&& value)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n    auto link_node = create_node(mystl::move(value));\n    ++size_;\n    return link_iter_node(pos, link_node->as_base());\n  }\n\n  iterator insert(const_iterator pos, size_type n, const value_type& value)\n  { \n    THROW_LENGTH_ERROR_IF(size_ > max_size() - n, \"list<T>'s size too big\");\n    return fill_insert(pos, n, value); \n  }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  iterator insert(const_iterator pos, Iter first, Iter last)\n  { \n    size_type n = mystl::distance(first, last);\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - n, \"list<T>'s size too big\");\n    return copy_insert(pos, n, first); \n  }\n\n  // push_front / push_back\n\n  void push_front(const value_type& value)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n    auto link_node = create_node(value);\n    link_nodes_at_front(link_node->as_base(), link_node->as_base());\n    ++size_;\n  }\n\n  void push_front(value_type&& value)\n  {\n    emplace_front(mystl::move(value));\n  }\n\n  void push_back(const value_type& value)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n    auto link_node = create_node(value);\n    link_nodes_at_back(link_node->as_base(), link_node->as_base());\n    ++size_;\n  }\n\n  void push_back(value_type&& value)\n  {\n    emplace_back(mystl::move(value));\n  }\n\n  // pop_front / pop_back\n\n  void pop_front() \n  {\n    MYSTL_DEBUG(!empty());\n    auto n = node_->next;\n    unlink_nodes(n, n);\n    destroy_node(n->as_node());\n    --size_;\n  }\n\n  void pop_back() \n  { \n    MYSTL_DEBUG(!empty());\n    auto n = node_->prev;\n    unlink_nodes(n, n);\n    destroy_node(n->as_node());\n    --size_;\n  }\n\n  // erase / clear\n\n  iterator erase(const_iterator pos);\n  iterator erase(const_iterator first, const_iterator last);\n\n  void     clear();\n\n  // resize\n\n  void     resize(size_type new_size) { resize(new_size, value_type()); }\n  void     resize(size_type new_size, const value_type& value);\n\n  void     swap(list& rhs) noexcept\n  {\n    mystl::swap(node_, rhs.node_);\n    mystl::swap(size_, rhs.size_);\n  }\n\n  // list 相关操作\n\n  void splice(const_iterator pos, list& other);\n  void splice(const_iterator pos, list& other, const_iterator it);\n  void splice(const_iterator pos, list& other, const_iterator first, const_iterator last);\n\n  void remove(const value_type& value)\n  { remove_if([&](const value_type& v) {return v == value; }); }\n  template <class UnaryPredicate>\n  void remove_if(UnaryPredicate pred);\n\n  void unique()\n  { unique(mystl::equal_to<T>()); }\n  template <class BinaryPredicate>\n  void unique(BinaryPredicate pred);\n\n  void merge(list& x)\n  { merge(x, mystl::less<T>()); }\n  template <class Compare>\n  void merge(list& x, Compare comp);\n\n  void sort()\n  { list_sort(begin(), end(), size(), mystl::less<T>()); }\n  template <class Compared>\n  void sort(Compared comp)\n  { list_sort(begin(), end(), size(), comp); }\n\n  void reverse();\n\nprivate:\n  // helper functions\n\n  // create / destroy node\n  template <class ...Args>\n  node_ptr create_node(Args&& ...agrs);\n  void     destroy_node(node_ptr p);\n\n  // initialize\n  void      fill_init(size_type n, const value_type& value);\n  template <class Iter>\n  void      copy_init(Iter first, Iter last);\n\n  // link / unlink\n  iterator  link_iter_node(const_iterator pos, base_ptr node);\n  void      link_nodes(base_ptr p, base_ptr first, base_ptr last);\n  void      link_nodes_at_front(base_ptr first, base_ptr last);\n  void      link_nodes_at_back(base_ptr first, base_ptr last);\n  void      unlink_nodes(base_ptr f, base_ptr l);\n\n  // assign\n  void      fill_assign(size_type n, const value_type& value);\n  template <class Iter>\n  void      copy_assign(Iter first, Iter last);\n\n  // insert\n  iterator  fill_insert(const_iterator pos, size_type n, const value_type& value);\n  template <class Iter>\n  iterator  copy_insert(const_iterator pos, size_type n, Iter first);\n\n  // sort\n  template <class Compared>\n  iterator  list_sort(iterator first, iterator last, size_type n, Compared comp);\n\n};\n\n/*****************************************************************************************/\n\n// 删除 pos 处的元素\ntemplate <class T>\ntypename list<T>::iterator \nlist<T>::erase(const_iterator pos)\n{\n  MYSTL_DEBUG(pos != cend());\n  auto n = pos.node_;\n  auto next = n->next;\n  unlink_nodes(n, n);\n  destroy_node(n->as_node());\n  --size_;\n  return iterator(next);\n}\n\n// 删除 [first, last) 内的元素\ntemplate <class T>\ntypename list<T>::iterator \nlist<T>::erase(const_iterator first, const_iterator last)\n{\n  if (first != last)\n  {\n    unlink_nodes(first.node_, last.node_->prev);\n    while (first != last)\n    {\n      auto cur = first.node_;\n      ++first;\n      destroy_node(cur->as_node());\n      --size_;\n    }\n  }\n  return iterator(last.node_);\n}\n\n// 清空 list\ntemplate <class T>\nvoid list<T>::clear()\n{\n  if (size_ != 0)\n  {\n    auto cur = node_->next;\n    for (base_ptr next = cur->next; cur != node_; cur = next, next = cur->next)\n    {\n      destroy_node(cur->as_node());\n    }\n    node_->unlink();\n    size_ = 0;\n  }\n}\n\n// 重置容器大小\ntemplate <class T>\nvoid list<T>::resize(size_type new_size, const value_type& value)\n{\n  auto i = begin();\n  size_type len = 0;\n  while (i != end() && len < new_size)\n  {\n    ++i;\n    ++len;\n  }\n  if (len == new_size)\n  {\n    erase(i, node_);\n  }\n  else\n  {\n    insert(node_, new_size - len, value);\n  }\n}\n\n// 将 list x 接合于 pos 之前\ntemplate <class T>\nvoid list<T>::splice(const_iterator pos, list& x)\n{\n  MYSTL_DEBUG(this != &x);\n  if (!x.empty())\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, \"list<T>'s size too big\");\n\n    auto f = x.node_->next;\n    auto l = x.node_->prev;\n\n    x.unlink_nodes(f, l);\n    link_nodes(pos.node_, f, l);\n\n    size_ += x.size_;\n    x.size_ = 0;\n  }\n}\n\n// 将 it 所指的节点接合于 pos 之前\ntemplate <class T>\nvoid list<T>::splice(const_iterator pos, list& x, const_iterator it)\n{\n  if (pos.node_ != it.node_ && pos.node_ != it.node_->next)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, \"list<T>'s size too big\");\n\n    auto f = it.node_;\n\n    x.unlink_nodes(f, f);\n    link_nodes(pos.node_, f, f);\n\n    ++size_;\n    --x.size_;\n  }\n}\n\n// 将 list x 的 [first, last) 内的节点接合于 pos 之前\ntemplate <class T>\nvoid list<T>::splice(const_iterator pos, list& x, const_iterator first, const_iterator last)\n{\n  if (first != last && this != &x)\n  {\n    size_type n = mystl::distance(first, last);\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - n, \"list<T>'s size too big\");\n    auto f = first.node_;\n    auto l = last.node_->prev;\n\n    x.unlink_nodes(f, l);\n    link_nodes(pos.node_, f, l);\n\n    size_ += n;\n    x.size_ -= n;\n  }\n}\n\n// 将另一元操作 pred 为 true 的所有元素移除\ntemplate <class T>\ntemplate <class UnaryPredicate>\nvoid list<T>::remove_if(UnaryPredicate pred)\n{\n  auto f = begin();\n  auto l = end();\n  for (auto next = f; f != l; f = next)\n  {\n    ++next;\n    if (pred(*f))\n    {\n      erase(f);\n    }\n  }\n}\n\n// 移除 list 中满足 pred 为 true 重复元素\ntemplate <class T>\ntemplate <class BinaryPredicate>\nvoid list<T>::unique(BinaryPredicate pred)\n{\n  auto i = begin();\n  auto e = end();\n  auto j = i;\n  ++j;\n  while (j != e)\n  {\n    if (pred(*i, *j))\n    {\n      erase(j);\n    }\n    else\n    {\n      i = j;\n    }\n    j = i;\n    ++j;\n  }\n}\n\n// 与另一个 list 合并，按照 comp 为 true 的顺序\ntemplate <class T>\ntemplate <class Compare>\nvoid list<T>::merge(list& x, Compare comp)\n{\n  if (this != &x)\n  {\n    THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, \"list<T>'s size too big\");\n\n    auto f1 = begin();\n    auto l1 = end();\n    auto f2 = x.begin();\n    auto l2 = x.end();\n\n    while (f1 != l1 && f2 != l2)\n    {\n      if (comp(*f2, *f1))\n      {\n        // 使 comp 为 true 的一段区间\n        auto next = f2;\n        ++next;\n        for (; next != l2 && comp(*next, *f1); ++next)\n          ;\n        auto f = f2.node_;\n        auto l = next.node_->prev;\n        f2 = next;\n\n        // link node\n        x.unlink_nodes(f, l);\n        link_nodes(f1.node_, f, l);\n        ++f1;\n      }\n      else\n      {\n        ++f1;\n      }\n    }\n    // 连接剩余部分\n    if (f2 != l2)\n    {\n      auto f = f2.node_;\n      auto l = l2.node_->prev;\n      x.unlink_nodes(f, l);\n      link_nodes(l1.node_, f, l);\n    }\n\n    size_ += x.size_;\n    x.size_ = 0;\n  }\n}\n\n// 将 list 反转\ntemplate <class T>\nvoid list<T>::reverse()\n{\n  if (size_ <= 1)\n  {\n    return;\n  }\n  auto i = begin();\n  auto e = end();\n  while (i.node_ != e.node_)\n  {\n    mystl::swap(i.node_->prev, i.node_->next);\n    i.node_ = i.node_->prev;\n  }\n  mystl::swap(e.node_->prev, e.node_->next);\n}\n\n/*****************************************************************************************/\n// helper function\n\n// 创建结点\ntemplate <class T>\ntemplate <class ...Args>\ntypename list<T>::node_ptr \nlist<T>::create_node(Args&& ...args)\n{\n  node_ptr p = node_allocator::allocate(1);\n  try\n  {\n    data_allocator::construct(mystl::address_of(p->value), mystl::forward<Args>(args)...);\n    p->prev = nullptr;\n    p->next = nullptr;\n  }\n  catch (...)\n  {\n    node_allocator::deallocate(p);\n    throw;\n  }\n  return p;\n}\n\n// 销毁结点\ntemplate <class T>\nvoid list<T>::destroy_node(node_ptr p)\n{\n  data_allocator::destroy(mystl::address_of(p->value));\n  node_allocator::deallocate(p);\n}\n\n// 用 n 个元素初始化容器\ntemplate <class T>\nvoid list<T>::fill_init(size_type n, const value_type& value)\n{\n  node_ = base_allocator::allocate(1);\n  node_->unlink();\n  size_ = n;\n  try\n  {\n    for (; n > 0; --n)\n    {\n      auto node = create_node(value);\n      link_nodes_at_back(node->as_base(), node->as_base());\n    }\n  }\n  catch (...)\n  {\n    clear();\n    base_allocator::deallocate(node_);\n    node_ = nullptr;\n    throw;\n  }\n}\n\n// 以 [first, last) 初始化容器\ntemplate <class T>\ntemplate <class Iter>\nvoid list<T>::copy_init(Iter first, Iter last)\n{\n  node_ = base_allocator::allocate(1);\n  node_->unlink();\n  size_type n = mystl::distance(first, last);\n  size_ = n;\n  try\n  {\n    for (; n > 0; --n, ++first)\n    {\n      auto node = create_node(*first);\n      link_nodes_at_back(node->as_base(), node->as_base());\n    }\n  }\n  catch (...)\n  {\n    clear();\n    base_allocator::deallocate(node_);\n    node_ = nullptr;\n    throw;\n  }\n}\n\n// 在 pos 处连接一个节点\ntemplate <class T>\ntypename list<T>::iterator \nlist<T>::link_iter_node(const_iterator pos, base_ptr link_node)\n{\n  if (pos == node_->next)\n  {\n    link_nodes_at_front(link_node, link_node);\n  }\n  else if (pos == node_)\n  {\n    link_nodes_at_back(link_node, link_node);\n  }\n  else\n  {\n    link_nodes(pos.node_, link_node, link_node);\n  }\n  return iterator(link_node);\n}\n\n// 在 pos 处连接 [first, last] 的结点\ntemplate <class T>\nvoid list<T>::link_nodes(base_ptr pos, base_ptr first, base_ptr last)\n{\n  pos->prev->next = first;\n  first->prev = pos->prev;\n  pos->prev = last;\n  last->next = pos;\n}\n\n// 在头部连接 [first, last] 结点\ntemplate <class T>\nvoid list<T>::link_nodes_at_front(base_ptr first, base_ptr last)\n{\n  first->prev = node_;\n  last->next = node_->next;\n  last->next->prev = last;\n  node_->next = first;\n}\n\n// 在尾部连接 [first, last] 结点\ntemplate <class T>\nvoid list<T>::link_nodes_at_back(base_ptr first, base_ptr last)\n{\n  last->next = node_;\n  first->prev = node_->prev;\n  first->prev->next = first;\n  node_->prev = last;\n}\n\n// 容器与 [first, last] 结点断开连接\ntemplate <class T>\nvoid list<T>::unlink_nodes(base_ptr first, base_ptr last)\n{\n  first->prev->next = last->next;\n  last->next->prev = first->prev;\n}\n\n// 用 n 个元素为容器赋值\ntemplate <class T>\nvoid list<T>::fill_assign(size_type n, const value_type& value)\n{\n  auto i = begin();\n  auto e = end();\n  for (; n > 0 && i != e; --n, ++i)\n  {\n    *i = value;\n  }\n  if (n > 0)\n  {\n    insert(e, n, value);\n  }\n  else\n  {\n    erase(i, e);\n  }\n}\n\n// 复制[f2, l2)为容器赋值\ntemplate <class T>\ntemplate <class Iter>\nvoid list<T>::copy_assign(Iter f2, Iter l2)\n{\n  auto f1 = begin();\n  auto l1 = end();\n  for (; f1 != l1 && f2 != l2; ++f1, ++f2)\n  {\n    *f1 = *f2;\n  }\n  if (f2 == l2)\n  {\n    erase(f1, l1);\n  }\n  else\n  {\n    insert(l1, f2, l2);\n  }\n}\n\n// 在 pos 处插入 n 个元素\ntemplate <class T>\ntypename list<T>::iterator \nlist<T>::fill_insert(const_iterator pos, size_type n, const value_type& value)\n{\n  iterator r(pos.node_);\n  if (n != 0)\n  {\n    const auto add_size = n;\n    auto node = create_node(value);\n    node->prev = nullptr;\n    r = iterator(node);\n    iterator end = r;\n    try\n    {\n      // 前面已经创建了一个节点，还需 n - 1 个\n      for (--n; n > 0; --n, ++end)\n      {\n        auto next = create_node(value);\n        end.node_->next = next->as_base();  // link node\n        next->prev = end.node_;\n      }\n      size_ += add_size;\n    }\n    catch (...)\n    {\n      auto enode = end.node_;\n      while (true)\n      {\n        auto prev = enode->prev;\n        destroy_node(enode->as_node());\n        if (prev == nullptr)\n          break;\n        enode = prev;\n      }\n      throw;\n    }\n    link_nodes(pos.node_, r.node_, end.node_);\n  }\n  return r;\n}\n\n// 在 pos 处插入 [first, last) 的元素\ntemplate <class T>\ntemplate <class Iter>\ntypename list<T>::iterator \nlist<T>::copy_insert(const_iterator pos, size_type n, Iter first)\n{\n  iterator r(pos.node_);\n  if (n != 0)\n  {\n    const auto add_size = n;\n    auto node = create_node(*first);\n    node->prev = nullptr;\n    r = iterator(node);\n    iterator end = r;\n    try\n    {\n      for (--n, ++first; n > 0; --n, ++first, ++end)\n      {\n        auto next = create_node(*first);\n        end.node_->next = next->as_base();  // link node\n        next->prev = end.node_;\n      }\n      size_ += add_size;\n    }\n    catch (...)\n    {\n      auto enode = end.node_;\n      while (true)\n      {\n        auto prev = enode->prev;\n        destroy_node(enode->as_node());\n        if (prev == nullptr)\n          break;\n        enode = prev;\n      }\n      throw;\n    }\n    link_nodes(pos.node_, r.node_, end.node_);\n  }\n  return r;\n}\n\n// 对 list 进行归并排序，返回一个迭代器指向区间最小元素的位置\ntemplate <class T>\ntemplate <class Compared>\ntypename list<T>::iterator \nlist<T>::list_sort(iterator f1, iterator l2, size_type n, Compared comp)\n{\n  if (n < 2)\n    return f1;\n\n  if (n == 2)\n  {\n    if (comp(*--l2, *f1))\n    {\n      auto ln = l2.node_;\n      unlink_nodes(ln, ln);\n      link_nodes(f1.node_, ln, ln);\n      return l2;\n    }\n    return f1;\n  }\n\n  auto n2 = n / 2;\n  auto l1 = f1;\n  mystl::advance(l1, n2);\n  auto result = f1 = list_sort(f1, l1, n2, comp);  // 前半段的最小位置\n  auto f2 = l1 = list_sort(l1, l2, n - n2, comp);  // 后半段的最小位置\n\n  // 把较小的一段区间移到前面\n  if (comp(*f2, *f1))\n  {\n    auto m = f2;\n    ++m;\n    for (; m != l2 && comp(*m, *f1); ++m)\n      ;\n    auto f = f2.node_;\n    auto l = m.node_->prev;\n    result = f2;\n    l1 = f2 = m;\n    unlink_nodes(f, l);\n    m = f1;\n    ++m;\n    link_nodes(f1.node_, f, l);\n    f1 = m;\n  }\n  else\n  {\n    ++f1;\n  }\n\n  // 合并两段有序区间\n  while (f1 != l1 && f2 != l2)\n  {\n    if (comp(*f2, *f1))\n    {\n      auto m = f2;\n      ++m;\n      for (; m != l2 && comp(*m, *f1); ++m)\n        ;\n      auto f = f2.node_;\n      auto l = m.node_->prev;\n      if (l1 == f2)\n        l1 = m;\n      f2 = m;\n      unlink_nodes(f, l);\n      m = f1;\n      ++m;\n      link_nodes(f1.node_, f, l);\n      f1 = m;\n    }\n    else\n    {\n      ++f1;\n    }\n  }\n  return result;\n}\n\n// 重载比较操作符\ntemplate <class T>\nbool operator==(const list<T>& lhs, const list<T>& rhs)\n{\n  auto f1 = lhs.cbegin();\n  auto f2 = rhs.cbegin();\n  auto l1 = lhs.cend();\n  auto l2 = rhs.cend();\n  for (; f1 != l1 && f2 != l2 && *f1 == *f2; ++f1, ++f2)\n    ;\n  return f1 == l1 && f2 == l2;\n}\n\ntemplate <class T>\nbool operator<(const list<T>& lhs, const list<T>& rhs)\n{\n  return mystl::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());\n}\n\ntemplate <class T>\nbool operator!=(const list<T>& lhs, const list<T>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class T>\nbool operator>(const list<T>& lhs, const list<T>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class T>\nbool operator<=(const list<T>& lhs, const list<T>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class T>\nbool operator>=(const list<T>& lhs, const list<T>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class T>\nvoid swap(list<T>& lhs, list<T>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_LIST_H_\n\n"
  },
  {
    "path": "MyTinySTL/map.h",
    "content": "﻿#ifndef MYTINYSTL_MAP_H_\n#define MYTINYSTL_MAP_H_\n\n// 这个头文件包含了两个模板类 map 和 multimap\n// map      : 映射，元素具有键值和实值，会根据键值大小自动排序，键值不允许重复\n// multimap : 映射，元素具有键值和实值，会根据键值大小自动排序，键值允许重复\n\n// notes:\n//\n// 异常保证：\n// mystl::map<Key, T> / mystl::multimap<Key, T> 满足基本异常保证，对以下等函数做强异常安全保证：\n//   * emplace\n//   * emplace_hint\n//   * insert\n\n#include \"rb_tree.h\"\n\nnamespace mystl\n{\n\n// 模板类 map，键值不允许重复\n// 参数一代表键值类型，参数二代表实值类型，参数三代表键值的比较方式，缺省使用 mystl::less\ntemplate <class Key, class T, class Compare = mystl::less<Key>>\nclass map\n{\npublic:\n  // map 的嵌套型别定义\n  typedef Key                        key_type;\n  typedef T                          mapped_type;\n  typedef mystl::pair<const Key, T>  value_type;\n  typedef Compare                    key_compare;\n\n  // 定义一个 functor，用来进行元素比较\n  class value_compare : public binary_function <value_type, value_type, bool>\n  {\n    friend class map<Key, T, Compare>;\n  private:\n    Compare comp;\n    value_compare(Compare c) : comp(c) {}\n  public:\n    bool operator()(const value_type& lhs, const value_type& rhs) const\n    {\n      return comp(lhs.first, rhs.first);  // 比较键值的大小\n    }\n  };\n\nprivate:\n  // 以 mystl::rb_tree 作为底层机制\n  typedef mystl::rb_tree<value_type, key_compare>  base_type;\n  base_type tree_;\n\npublic:\n  // 使用 rb_tree 的型别\n  typedef typename base_type::node_type              node_type;\n  typedef typename base_type::pointer                pointer;\n  typedef typename base_type::const_pointer          const_pointer;\n  typedef typename base_type::reference              reference;\n  typedef typename base_type::const_reference        const_reference;\n  typedef typename base_type::iterator               iterator;\n  typedef typename base_type::const_iterator         const_iterator;\n  typedef typename base_type::reverse_iterator       reverse_iterator;\n  typedef typename base_type::const_reverse_iterator const_reverse_iterator;\n  typedef typename base_type::size_type              size_type;\n  typedef typename base_type::difference_type        difference_type;\n  typedef typename base_type::allocator_type         allocator_type;\n\npublic:\n  // 构造、复制、移动、赋值函数\n\n  map() = default;\n\n  template <class InputIterator>\n  map(InputIterator first, InputIterator last)\n    :tree_()\n  { tree_.insert_unique(first, last); }\n\n  map(std::initializer_list<value_type> ilist) \n    :tree_()\n  { tree_.insert_unique(ilist.begin(), ilist.end()); }\n\n  map(const map& rhs) \n    :tree_(rhs.tree_) \n  {\n  }\n  map(map&& rhs) noexcept\n    :tree_(mystl::move(rhs.tree_))\n  {\n  }\n\n  map& operator=(const map& rhs)\n  { \n    tree_ = rhs.tree_; \n    return *this;\n  }\n  map& operator=(map&& rhs)\n  { \n    tree_ = mystl::move(rhs.tree_);\n    return *this;\n  }\n\n  map& operator=(std::initializer_list<value_type> ilist)\n  {\n    tree_.clear();\n    tree_.insert_unique(ilist.begin(), ilist.end());\n    return *this;\n  }\n\n  // 相关接口\n\n  key_compare            key_comp()      const { return tree_.key_comp(); }\n  value_compare          value_comp()    const { return value_compare(tree_.key_comp()); }\n  allocator_type         get_allocator() const { return tree_.get_allocator(); }\n\n  // 迭代器相关\n\n  iterator               begin()         noexcept\n  { return tree_.begin(); }\n  const_iterator         begin()   const noexcept\n  { return tree_.begin(); }\n  iterator               end()           noexcept\n  { return tree_.end(); }\n  const_iterator         end()     const noexcept\n  { return tree_.end(); }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return const_reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return const_reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关\n  bool                   empty()    const noexcept { return tree_.empty(); }\n  size_type              size()     const noexcept { return tree_.size(); }\n  size_type              max_size() const noexcept { return tree_.max_size(); }\n\n  // 访问元素相关\n\n  // 若键值不存在，at 会抛出一个异常\n  mapped_type& at(const key_type& key)\n  {\n    iterator it = lower_bound(key);\n    // it->first >= key\n    THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key),\n                          \"map<Key, T> no such element exists\");\n    return it->second;\n  }\n  const mapped_type& at(const key_type& key) const\n  {\n    const_iterator it = lower_bound(key);\n    // it->first >= key\n    THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key),\n                          \"map<Key, T> no such element exists\");\n    return it->second;\n  }\n\n  mapped_type& operator[](const key_type& key)\n  {\n    iterator it = lower_bound(key);\n    // it->first >= key\n    if (it == end() || key_comp()(key, it->first))\n      it = emplace_hint(it, key, T{});\n    return it->second;\n  }\n  mapped_type& operator[](key_type&& key)\n  {\n    iterator it = lower_bound(key);\n    // it->first >= key\n    if (it == end() || key_comp()(key, it->first))\n      it = emplace_hint(it, mystl::move(key), T{});\n    return it->second;\n  }\n\n  // 插入删除相关\n\n  template <class ...Args>\n  pair<iterator, bool> emplace(Args&& ...args)\n  {\n    return tree_.emplace_unique(mystl::forward<Args>(args)...);\n  }\n\n  template <class ...Args>\n  iterator emplace_hint(iterator hint, Args&& ...args)\n  {\n    return tree_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...);\n  }\n\n  pair<iterator, bool> insert(const value_type& value)\n  {\n    return tree_.insert_unique(value);\n  }\n  pair<iterator, bool> insert(value_type&& value)\n  {\n    return tree_.insert_unique(mystl::move(value));\n  }\n\n  iterator insert(iterator hint, const value_type& value)\n  {\n    return tree_.insert_unique(hint, value);\n  }\n  iterator insert(iterator hint, value_type&& value)\n  {\n    return tree_.insert_unique(hint, mystl::move(value));\n  }\n\n  template <class InputIterator>\n  void insert(InputIterator first, InputIterator last)\n  {\n    tree_.insert_unique(first, last);\n  }\n\n  void      erase(iterator position)             { tree_.erase(position); }\n  size_type erase(const key_type& key)           { return tree_.erase_unique(key); }\n  void      erase(iterator first, iterator last) { tree_.erase(first, last); }\n\n  void      clear()                              { tree_.clear(); }\n\n  // map 相关操作\n\n  iterator       find(const key_type& key)              { return tree_.find(key); }\n  const_iterator find(const key_type& key)        const { return tree_.find(key); }\n\n  size_type      count(const key_type& key)       const { return tree_.count_unique(key); }\n\n  iterator       lower_bound(const key_type& key)       { return tree_.lower_bound(key); }\n  const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }\n\n  iterator       upper_bound(const key_type& key)       { return tree_.upper_bound(key); }\n  const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }\n\n  pair<iterator, iterator>\n    equal_range(const key_type& key) \n  { return tree_.equal_range_unique(key); }\n\n  pair<const_iterator, const_iterator>\n    equal_range(const key_type& key) const \n  { return tree_.equal_range_unique(key); }\n\n  void           swap(map& rhs) noexcept\n  { tree_.swap(rhs.tree_); }\n\npublic:\n  friend bool operator==(const map& lhs, const map& rhs) { return lhs.tree_ == rhs.tree_; }\n  friend bool operator< (const map& lhs, const map& rhs) { return lhs.tree_ <  rhs.tree_; }\n};\n\n// 重载比较操作符\ntemplate <class Key, class T, class Compare>\nbool operator==(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator<(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)\n{\n  return lhs < rhs;\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator!=(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator>(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator<=(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator>=(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class T, class Compare>\nvoid swap(map<Key, T, Compare>& lhs, map<Key, T, Compare>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n/*****************************************************************************************/\n\n// 模板类 multimap，键值允许重复\n// 参数一代表键值类型，参数二代表实值类型，参数三代表键值的比较方式，缺省使用 mystl::less\ntemplate <class Key, class T, class Compare = mystl::less<Key>>\nclass multimap\n{\npublic:\n  // multimap 的型别定义\n  typedef Key                        key_type;\n  typedef T                          mapped_type;\n  typedef mystl::pair<const Key, T>  value_type;\n  typedef Compare                    key_compare;\n\n  // 定义一个 functor，用来进行元素比较\n  class value_compare : public binary_function <value_type, value_type, bool>\n  {\n    friend class multimap<Key, T, Compare>;\n  private:\n    Compare comp;\n    value_compare(Compare c) : comp(c) {}\n  public:\n    bool operator()(const value_type& lhs, const value_type& rhs) const\n    {\n      return comp(lhs.first, rhs.first);\n    }\n  };\n\nprivate:\n  // 用 mystl::rb_tree 作为底层机制\n  typedef mystl::rb_tree<value_type, key_compare>  base_type;\n  base_type tree_;\n\npublic:\n  // 使用 rb_tree 的型别\n  typedef typename base_type::node_type              node_type;\n  typedef typename base_type::pointer                pointer;\n  typedef typename base_type::const_pointer          const_pointer;\n  typedef typename base_type::reference              reference;\n  typedef typename base_type::const_reference        const_reference;\n  typedef typename base_type::iterator               iterator;\n  typedef typename base_type::const_iterator         const_iterator;\n  typedef typename base_type::reverse_iterator       reverse_iterator;\n  typedef typename base_type::const_reverse_iterator const_reverse_iterator;\n  typedef typename base_type::size_type              size_type;\n  typedef typename base_type::difference_type        difference_type;\n  typedef typename base_type::allocator_type         allocator_type;\n\npublic:\n  // 构造、复制、移动函数\n\n  multimap() = default;\n\n  template <class InputIterator>\n  multimap(InputIterator first, InputIterator last) \n    :tree_() \n  { tree_.insert_multi(first, last); }\n  multimap(std::initializer_list<value_type> ilist) \n    :tree_() \n  { tree_.insert_multi(ilist.begin(), ilist.end()); }\n\n  multimap(const multimap& rhs)\n    :tree_(rhs.tree_)\n  {\n  }\n  multimap(multimap&& rhs) noexcept\n    :tree_(mystl::move(rhs.tree_))\n  {\n  }\n\n  multimap& operator=(const multimap& rhs) \n  { \n    tree_ = rhs.tree_; \n    return *this; \n  }\n  multimap& operator=(multimap&& rhs) \n  { \n    tree_ = mystl::move(rhs.tree_);\n    return *this; \n  }\n\n  multimap& operator=(std::initializer_list<value_type> ilist)\n  {\n    tree_.clear();\n    tree_.insert_multi(ilist.begin(), ilist.end());\n    return *this;\n  }\n\n  // 相关接口\n\n  key_compare            key_comp()      const { return tree_.key_comp(); }\n  value_compare          value_comp()    const { return value_compare(tree_.key_comp()); }\n  allocator_type         get_allocator() const { return tree_.get_allocator(); }\n\n  // 迭代器相关\n\n  iterator               begin()         noexcept\n  { return tree_.begin(); }\n  const_iterator         begin()   const noexcept\n  { return tree_.begin(); }\n  iterator               end()           noexcept\n  { return tree_.end(); }\n  const_iterator         end()     const noexcept\n  { return tree_.end(); }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return const_reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return const_reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关\n  bool                   empty()    const noexcept { return tree_.empty(); }\n  size_type              size()     const noexcept { return tree_.size(); }\n  size_type              max_size() const noexcept { return tree_.max_size(); }\n\n  // 插入删除操作\n\n  template <class ...Args>\n  iterator emplace(Args&& ...args)\n  {\n    return tree_.emplace_multi(mystl::forward<Args>(args)...);\n  }\n\n  template <class ...Args>\n  iterator emplace_hint(iterator hint, Args&& ...args)\n  {\n    return tree_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...);\n  }\n\n  iterator insert(const value_type& value)\n  {\n    return tree_.insert_multi(value);\n  }\n  iterator insert(value_type&& value)\n  {\n    return tree_.insert_multi(mystl::move(value));\n  }\n\n  iterator insert(iterator hint, const value_type& value)\n  {\n    return tree_.insert_multi(hint, value);\n  }\n  iterator insert(iterator hint, value_type&& value)\n  {\n    return tree_.insert_multi(hint, mystl::move(value));\n  }\n\n  template <class InputIterator>\n  void insert(InputIterator first, InputIterator last)\n  {\n    tree_.insert_multi(first, last);\n  }\n\n  void           erase(iterator position)             { tree_.erase(position); }\n  size_type      erase(const key_type& key)           { return tree_.erase_multi(key); }\n  void           erase(iterator first, iterator last) { tree_.erase(first, last); }\n\n  void           clear() { tree_.clear(); }\n\n  // multimap 相关操作\n\n  iterator       find(const key_type& key)              { return tree_.find(key); }\n  const_iterator find(const key_type& key)        const { return tree_.find(key); }\n\n  size_type      count(const key_type& key)       const { return tree_.count_multi(key); }\n\n  iterator       lower_bound(const key_type& key)       { return tree_.lower_bound(key); }\n  const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }\n\n  iterator       upper_bound(const key_type& key)       { return tree_.upper_bound(key); }\n  const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }\n\n  pair<iterator, iterator> \n    equal_range(const key_type& key)\n  { return tree_.equal_range_multi(key); }\n\n  pair<const_iterator, const_iterator>\n    equal_range(const key_type& key) const \n  { return tree_.equal_range_multi(key); }\n\n  void swap(multimap& rhs) noexcept\n  { tree_.swap(rhs.tree_); }\n\npublic:\n  friend bool operator==(const multimap& lhs, const multimap& rhs) { return lhs.tree_ == rhs.tree_; }\n  friend bool operator< (const multimap& lhs, const multimap& rhs) { return lhs.tree_ <  rhs.tree_; }\n};\n\n// 重载比较操作符\ntemplate <class Key, class T, class Compare>\nbool operator==(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator<(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)\n{\n  return lhs < rhs;\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator!=(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator>(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator<=(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class Key, class T, class Compare>\nbool operator>=(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class T, class Compare>\nvoid swap(multimap<Key, T, Compare>& lhs, multimap<Key, T, Compare>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_MAP_H_\n\n"
  },
  {
    "path": "MyTinySTL/memory.h",
    "content": "﻿#ifndef MYTINYSTL_MEMORY_H_\n#define MYTINYSTL_MEMORY_H_\n\n// 这个头文件负责更高级的动态内存管理\n// 包含一些基本函数、空间配置器、未初始化的储存空间管理，以及一个模板类 auto_ptr\n\n#include <cstddef>\n#include <cstdlib>\n#include <climits>\n\n#include \"algobase.h\"\n#include \"allocator.h\"\n#include \"construct.h\"\n#include \"uninitialized.h\"\n\nnamespace mystl\n{\n\n// 获取对象地址\ntemplate <class Tp>\nconstexpr Tp* address_of(Tp& value) noexcept\n{\n  return &value;\n}\n\n// 获取 / 释放 临时缓冲区\n\ntemplate <class T>\npair<T*, ptrdiff_t> get_buffer_helper(ptrdiff_t len, T*)\n{\n  if (len > static_cast<ptrdiff_t>(INT_MAX / sizeof(T)))\n    len = INT_MAX / sizeof(T);\n  while (len > 0)\n  {\n    T* tmp = static_cast<T*>(malloc(static_cast<size_t>(len) * sizeof(T)));\n    if (tmp)\n      return pair<T*, ptrdiff_t>(tmp, len);\n    len /= 2;  // 申请失败时减少 len 的大小\n  }\n  return pair<T*, ptrdiff_t>(nullptr, 0);\n}\n\ntemplate <class T>\npair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t len)\n{\n  return get_buffer_helper(len, static_cast<T*>(0));\n}\n\ntemplate <class T>\npair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t len, T*)\n{\n  return get_buffer_helper(len, static_cast<T*>(0));\n}\n\ntemplate <class T>\nvoid release_temporary_buffer(T* ptr)\n{\n  free(ptr);\n}\n\n// --------------------------------------------------------------------------------------\n// 类模板 : temporary_buffer\n// 进行临时缓冲区的申请与释放\ntemplate <class ForwardIterator, class T>\nclass temporary_buffer\n{\nprivate:\n  ptrdiff_t original_len;  // 缓冲区申请的大小\n  ptrdiff_t len;           // 缓冲区实际的大小\n  T*        buffer;        // 指向缓冲区的指针\n\npublic:\n  // 构造、析构函数\n  temporary_buffer(ForwardIterator first, ForwardIterator last);\n\n  ~temporary_buffer()\n  {\n    mystl::destroy(buffer, buffer + len);\n    free(buffer);\n  }\n\npublic:\n\n  ptrdiff_t size()           const noexcept { return len; }\n  ptrdiff_t requested_size() const noexcept { return original_len; }\n  T*        begin()                noexcept { return buffer; }\n  T*        end()                  noexcept { return buffer + len; }\n\nprivate:\n  void allocate_buffer();\n  void initialize_buffer(const T&, std::true_type) {}\n  void initialize_buffer(const T& value, std::false_type)\n  { mystl::uninitialized_fill_n(buffer, len, value); }\n\nprivate:\n  temporary_buffer(const temporary_buffer&);\n  void operator=(const temporary_buffer&);\n};\n\n// 构造函数\ntemplate <class ForwardIterator, class T>\ntemporary_buffer<ForwardIterator, T>::\ntemporary_buffer(ForwardIterator first, ForwardIterator last)\n{\n  try\n  {\n    len = mystl::distance(first, last);\n    allocate_buffer();\n    if (len > 0)\n    {\n      initialize_buffer(*first, std::is_trivially_default_constructible<T>());\n    }\n  }\n  catch (...)\n  {\n    free(buffer);\n    buffer = nullptr;\n    len = 0;\n  }\n}\n\n// allocate_buffer 函数\ntemplate <class ForwardIterator, class T>\nvoid temporary_buffer<ForwardIterator, T>::allocate_buffer()\n{\n  original_len = len;\n  if (len > static_cast<ptrdiff_t>(INT_MAX / sizeof(T)))\n    len = INT_MAX / sizeof(T);\n  while (len > 0)\n  {\n    buffer = static_cast<T*>(malloc(len * sizeof(T)));\n    if (buffer)\n      break;\n    len /= 2;  // 申请失败时减少申请空间大小\n  }\n}\n\n// --------------------------------------------------------------------------------------\n// 模板类: auto_ptr\n// 一个具有严格对象所有权的小型智能指针\ntemplate <class T>\nclass auto_ptr\n{\npublic:\n  typedef T    elem_type;\n\nprivate:\n  T* m_ptr;  // 实际指针\n\npublic:\n  // 构造、复制、析构函数\n  explicit auto_ptr(T* p = nullptr) :m_ptr(p) {}\n  auto_ptr(auto_ptr& rhs) :m_ptr(rhs.release()) {}\n  template <class U>\n  auto_ptr(auto_ptr<U>& rhs) : m_ptr(rhs.release()) {}\n\n  auto_ptr& operator=(auto_ptr& rhs)\n  {\n    if (this != &rhs)\n    {\n      delete m_ptr;\n      m_ptr = rhs.release();\n    }\n    return *this;\n  }\n  template <class U>\n  auto_ptr& operator=(auto_ptr<U>& rhs)\n  {\n    if (this->get() != rhs.get())\n    {\n      delete m_ptr;\n      m_ptr = rhs.release();\n    }\n    return *this;\n  }\n\n  ~auto_ptr() { delete m_ptr; }\n\npublic:\n  // 重载 operator* 和 operator->\n  T& operator*()  const { return *m_ptr; }\n  T* operator->() const { return m_ptr; }\n\n  // 获得指针\n  T* get() const { return m_ptr; }\n\n  // 释放指针\n  T* release()\n  {\n    T* tmp = m_ptr;\n    m_ptr = nullptr;\n    return tmp;\n  }\n\n  // 重置指针\n  void reset(T* p = nullptr)\n  {\n    if (m_ptr != p)\n    {\n      delete m_ptr;\n      m_ptr = p;\n    }\n  }\n};\n\n} // namespace mystl\n#endif // !MYTINYSTL_MEMORY_H_\n\n"
  },
  {
    "path": "MyTinySTL/numeric.h",
    "content": "﻿#ifndef MYTINYSTL_NUMERIC_H_\n#define MYTINYSTL_NUMERIC_H_\n\n// 这个头文件包含了 mystl 的数值算法\n\n#include \"iterator.h\"\n\nnamespace mystl\n{\n\n/*****************************************************************************************/\n// accumulate\n// 版本1：以初值 init 对每个元素进行累加\n// 版本2：以初值 init 对每个元素进行二元操作\n/*****************************************************************************************/\n// 版本1\ntemplate <class InputIter, class T>\nT accumulate(InputIter first, InputIter last, T init)\n{\n  for (; first != last; ++first)\n  {\n    init += *first;\n  }\n  return init;\n}\n\n// 版本2\ntemplate <class InputIter, class T, class BinaryOp>\nT accumulate(InputIter first, InputIter last, T init, BinaryOp binary_op)\n{\n  for (; first != last; ++first)\n  {\n    init = binary_op(init, *first);\n  }\n  return init;\n}\n\n/*****************************************************************************************/\n// adjacent_difference\n// 版本1：计算相邻元素的差值，结果保存到以 result 为起始的区间上\n// 版本2：自定义相邻元素的二元操作\n/*****************************************************************************************/\n// 版本1\ntemplate <class InputIter, class OutputIter>\nOutputIter adjacent_difference(InputIter first, InputIter last, OutputIter result)\n{\n  if (first == last)  return result;\n  *result = *first;  // 记录第一个元素\n  auto value = *first;\n  while (++first != last)\n  {\n    auto tmp = *first;\n    *++result = tmp - value;\n    value = tmp;\n  }\n  return ++result;\n}\n\n// 版本2\ntemplate <class InputIter, class OutputIter, class BinaryOp>\nOutputIter adjacent_difference(InputIter first, InputIter last, OutputIter result,\n                               BinaryOp binary_op)\n{\n  if (first == last)  return result;\n  *result = *first;  // 记录第一个元素\n  auto value = *first;\n  while (++first != last)\n  {\n    auto tmp = *first;\n    *++result = binary_op(tmp, value);\n    value = tmp;\n  }\n  return ++result;\n}\n\n/*****************************************************************************************/\n// inner_product\n// 版本1：以 init 为初值，计算两个区间的内积   \n// 版本2：自定义 operator+ 和 operator*\n/*****************************************************************************************/\n// 版本1\ntemplate <class InputIter1, class InputIter2, class T>\nT inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, T init)\n{\n  for (; first1 != last1; ++first1, ++first2)\n  {\n    init = init + (*first1 * *first2);\n  }\n  return init;\n}\n\n// 版本2\ntemplate <class InputIter1, class InputIter2, class T, class BinaryOp1, class BinaryOp2>\nT inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, T init,\n                BinaryOp1 binary_op1, BinaryOp2 binary_op2)\n{\n  for (; first1 != last1; ++first1, ++first2)\n  {\n    init = binary_op1(init, binary_op2(*first1, *first2));\n  }\n  return init;\n}\n\n/*****************************************************************************************/\n// iota\n// 填充[first, last)，以 value 为初值开始递增\n/*****************************************************************************************/\ntemplate <class ForwardIter, class T>\nvoid iota(ForwardIter first, ForwardIter last, T value)\n{\n  while (first != last)\n  {\n    *first++ = value;\n    ++value;\n  }\n}\n\n/*****************************************************************************************/\n// partial_sum\n// 版本1：计算局部累计求和，结果保存到以 result 为起始的区间上\n// 版本2：进行局部进行自定义二元操作\n/*****************************************************************************************/\ntemplate <class InputIter, class OutputIter>\nOutputIter partial_sum(InputIter first, InputIter last, OutputIter result)\n{\n  if (first == last)  return result;\n  *result = *first;  // 记录第一个元素\n  auto value = *first;\n  while (++first != last)\n  {\n    value = value + *first;\n    *++result = value;\n  }\n  return ++result;\n}\n\n// 版本2\ntemplate <class InputIter, class OutputIter, class BinaryOp>\nOutputIter partial_sum(InputIter first, InputIter last, OutputIter result,\n                       BinaryOp binary_op)\n{\n  if (first == last)  return result;\n  *result = *first;  //记录第一个元素\n  auto value = *first;\n  while (++first != last)\n  {\n    value = binary_op(value, *first);\n    *++result = value;\n  }\n  return ++result;\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_NUMERIC_H_\n\n"
  },
  {
    "path": "MyTinySTL/queue.h",
    "content": "﻿#ifndef MYTINYSTL_QUEUE_H_\n#define MYTINYSTL_QUEUE_H_\n\n// 这个头文件包含了两个模板类 queue 和 priority_queue\n// queue          : 队列\n// priority_queue : 优先队列\n\n#include \"deque.h\"\n#include \"vector.h\"\n#include \"functional.h\"\n#include \"heap_algo.h\"\n\nnamespace mystl\n{\n\n// 模板类 queue\n// 参数一代表数据类型，参数二代表底层容器类型，缺省使用 mystl::deque 作为底层容器\ntemplate <class T, class Container = mystl::deque<T>>\nclass queue\n{\npublic:\n  typedef Container                           container_type;\n  // 使用底层容器的型别\n  typedef typename Container::value_type      value_type;\n  typedef typename Container::size_type       size_type;\n  typedef typename Container::reference       reference;\n  typedef typename Container::const_reference const_reference;\n\n  static_assert(std::is_same<T, value_type>::value,\n                \"the value_type of Container should be same with T\");\nprivate:\n  container_type c_;  // 用底层容器表现 queue\n\npublic:\n  // 构造、复制、移动函数\n\n  queue() = default;\n\n  explicit queue(size_type n) \n    :c_(n) \n  {\n  }\n  queue(size_type n, const value_type& value)\n    :c_(n, value)\n  {\n  }\n\n  template <class IIter>\n  queue(IIter first, IIter last)\n    :c_(first, last) \n  {\n  }\n\n  queue(std::initializer_list<T> ilist)\n    :c_(ilist.begin(), ilist.end()) \n  {\n  }\n\n  queue(const Container& c) \n    :c_(c) \n  {\n  }\n  queue(Container&& c) noexcept(std::is_nothrow_move_constructible<Container>::value)\n    :c_(mystl::move(c)) \n  {\n  }\n\n  queue(const queue& rhs) \n    :c_(rhs.c_) \n  {\n  }\n  queue(queue&& rhs) noexcept(std::is_nothrow_move_constructible<Container>::value)\n    :c_(mystl::move(rhs.c_)) \n  {\n  }\n\n  queue& operator=(const queue& rhs) \n  {\n    c_ = rhs.c_; \n    return *this; \n  }\n  queue& operator=(queue&& rhs) noexcept(std::is_nothrow_move_assignable<Container>::value)\n  { \n    c_ = mystl::move(rhs.c_);\n    return *this;\n  }\n\n  queue& operator=(std::initializer_list<T> ilist)\n  { \n    c_ = ilist; \n    return *this; \n  }\n\n  ~queue() = default;\n\n  // 访问元素相关操作\n  reference       front()       { return c_.front(); }\n  const_reference front() const { return c_.front(); }\n  reference       back()        { return c_.back(); }\n  const_reference back()  const { return c_.back(); }\n\n  // 容量相关操作\n  bool      empty() const noexcept { return c_.empty(); }\n  size_type size()  const noexcept { return c_.size(); }\n\n  // 修改容器相关操作\n  template <class ...Args>\n  void emplace(Args&& ...args)\n  { c_.emplace_back(mystl::forward<Args>(args)...); }\n\n  void push(const value_type& value) \n  { c_.push_back(value); }\n  void push(value_type&& value)      \n  { c_.emplace_back(mystl::move(value)); }\n\n  void pop()                         \n  { c_.pop_front(); }\n\n  void clear()         \n  { \n    while (!empty())\n      pop(); \n  }\n\n  void swap(queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)))\n  { mystl::swap(c_, rhs.c_); }\n\npublic:\n  friend bool operator==(const queue& lhs, const queue& rhs) { return lhs.c_ == rhs.c_; }\n  friend bool operator< (const queue& lhs, const queue& rhs) { return lhs.c_ <  rhs.c_; }\n};\n\n// 重载比较操作符\ntemplate <class T, class Container>\nbool operator==(const queue<T, Container>& lhs, const queue<T, Container>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class T, class Container>\nbool operator!=(const queue<T, Container>& lhs, const queue<T, Container>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class T, class Container>\nbool operator<(const queue<T, Container>& lhs, const queue<T, Container>& rhs)\n{\n  return lhs < rhs;\n}\n\ntemplate <class T, class Container>\nbool operator>(const queue<T, Container>& lhs, const queue<T, Container>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class T, class Container>\nbool operator<=(const queue<T, Container>& lhs, const queue<T, Container>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class T, class Container>\nbool operator>=(const queue<T, Container>& lhs, const queue<T, Container>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class T, class Container>\nvoid swap(queue<T, Container>& lhs, queue<T, Container>& rhs) noexcept(noexcept(lhs.swap(rhs)))\n{\n  lhs.swap(rhs);\n}\n\n/*****************************************************************************************/\n\n// 模板类 priority_queue\n// 参数一代表数据类型，参数二代表容器类型，缺省使用 mystl::vector 作为底层容器\n// 参数三代表比较权值的方式，缺省使用 mystl::less 作为比较方式\ntemplate <class T, class Container = mystl::vector<T>,\n  class Compare = mystl::less<typename Container::value_type>>\nclass priority_queue\n{\npublic:\n  typedef Container                           container_type;\n  typedef Compare                             value_compare;\n  // 使用底层容器的型别\n  typedef typename Container::value_type      value_type;\n  typedef typename Container::size_type       size_type;\n  typedef typename Container::reference       reference;\n  typedef typename Container::const_reference const_reference;\n\n  static_assert(std::is_same<T, value_type>::value,\n                \"the value_type of Container should be same with T\");\n\nprivate:\n  container_type c_;     // 用底层容器来表现 priority_queue\n  value_compare  comp_;  // 权值比较的标准\n\npublic:\n  // 构造、复制、移动函数\n  priority_queue() = default;\n\n  priority_queue(const Compare& c) \n    :c_(), comp_(c) \n  {\n  }\n\n  explicit priority_queue(size_type n)\n    :c_(n)\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n  priority_queue(size_type n, const value_type& value) \n    :c_(n, value)\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n\n  template <class IIter>\n  priority_queue(IIter first, IIter last) \n    :c_(first, last)\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n\n  priority_queue(std::initializer_list<T> ilist)\n    :c_(ilist)\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n\n  priority_queue(const Container& s)\n    :c_(s)\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n  priority_queue(Container&& s) \n    :c_(mystl::move(s))\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n\n  priority_queue(const priority_queue& rhs)\n    :c_(rhs.c_), comp_(rhs.comp_)\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n  priority_queue(priority_queue&& rhs) \n    :c_(mystl::move(rhs.c_)), comp_(rhs.comp_)\n  {\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n  }\n\n  priority_queue& operator=(const priority_queue& rhs)\n  {\n    c_ = rhs.c_;\n    comp_ = rhs.comp_;\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n    return *this;\n  }\n  priority_queue& operator=(priority_queue&& rhs)\n  {\n    c_ = mystl::move(rhs.c_);\n    comp_ = rhs.comp_;\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n    return *this;\n  }\n  priority_queue& operator=(std::initializer_list<T> ilist)\n  {\n    c_ = ilist;\n    comp_ = value_compare();\n    mystl::make_heap(c_.begin(), c_.end(), comp_);\n    return *this;\n  }\n\n  ~priority_queue() = default;\n\npublic:\n\n  // 访问元素相关操作\n  const_reference top() const { return c_.front(); }\n\n  // 容量相关操作\n  bool      empty() const noexcept { return c_.empty(); }\n  size_type size()  const noexcept { return c_.size(); }\n\n  // 修改容器相关操作\n  template <class... Args>\n  void emplace(Args&& ...args)\n  {\n    c_.emplace_back(mystl::forward<Args>(args)...);\n    mystl::push_heap(c_.begin(), c_.end(), comp_);\n  }\n\n  void push(const value_type& value)\n  {\n    c_.push_back(value);\n    mystl::push_heap(c_.begin(), c_.end(), comp_);\n  }\n  void push(value_type&& value)\n  {\n    c_.push_back(mystl::move(value));\n    mystl::push_heap(c_.begin(), c_.end(), comp_);\n  }\n\n  void pop()\n  {\n    mystl::pop_heap(c_.begin(), c_.end(), comp_);\n    c_.pop_back();\n  }\n\n  void clear()\n  {\n    while (!empty())\n      pop();\n  }\n\n  void swap(priority_queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)) &&\n                                          noexcept(mystl::swap(comp_, rhs.comp_)))\n  {\n    mystl::swap(c_, rhs.c_);\n    mystl::swap(comp_, rhs.comp_);\n  }\n\npublic:\n  friend bool operator==(const priority_queue& lhs, const priority_queue& rhs)\n  {\n    return lhs.c_ == rhs.c_;\n  }\n  friend bool operator!=(const priority_queue& lhs, const priority_queue& rhs)\n  {\n    return lhs.c_ != rhs.c_;\n  }\n};\n\n// 重载比较操作符\ntemplate <class T, class Container, class Compare>\nbool operator==(priority_queue<T, Container, Compare>& lhs,\n                priority_queue<T, Container, Compare>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class T, class Container, class Compare>\nbool operator!=(priority_queue<T, Container, Compare>& lhs,\n                priority_queue<T, Container, Compare>& rhs)\n{\n  return lhs != rhs;\n}\n\n// 重载 mystl 的 swap\ntemplate <class T, class Container, class Compare>\nvoid swap(priority_queue<T, Container, Compare>& lhs, \n          priority_queue<T, Container, Compare>& rhs) noexcept(noexcept(lhs.swap(rhs)))\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_QUEUE_H_\n\n"
  },
  {
    "path": "MyTinySTL/rb_tree.h",
    "content": "﻿#ifndef MYTINYSTL_RB_TREE_H_\n#define MYTINYSTL_RB_TREE_H_\n\n// 这个头文件包含一个模板类 rb_tree\n// rb_tree : 红黑树\n\n#include <initializer_list>\n\n#include <cassert>\n\n#include \"functional.h\"\n#include \"iterator.h\"\n#include \"memory.h\"\n#include \"type_traits.h\"\n#include \"exceptdef.h\"\n\nnamespace mystl\n{\n\n// rb tree 节点颜色的类型\n\ntypedef bool rb_tree_color_type;\n\nstatic constexpr rb_tree_color_type rb_tree_red   = false;\nstatic constexpr rb_tree_color_type rb_tree_black = true;\n\n// forward declaration\n\ntemplate <class T> struct rb_tree_node_base;\ntemplate <class T> struct rb_tree_node;\n\ntemplate <class T> struct rb_tree_iterator;\ntemplate <class T> struct rb_tree_const_iterator;\n\n// rb tree value traits\n\ntemplate <class T, bool>\nstruct rb_tree_value_traits_imp\n{\n  typedef T key_type;\n  typedef T mapped_type;\n  typedef T value_type;\n\n  template <class Ty>\n  static const key_type& get_key(const Ty& value)\n  {\n    return value;\n  }\n\n  template <class Ty>\n  static const value_type& get_value(const Ty& value)\n  {\n    return value;\n  }\n};\n\ntemplate <class T>\nstruct rb_tree_value_traits_imp<T, true>\n{\n  typedef typename std::remove_cv<typename T::first_type>::type key_type;\n  typedef typename T::second_type                               mapped_type;\n  typedef T                                                     value_type;\n\n  template <class Ty>\n  static const key_type& get_key(const Ty& value)\n  {\n    return value.first;\n  }\n\n  template <class Ty>\n  static const value_type& get_value(const Ty& value)\n  {\n    return value;\n  }\n};\n\ntemplate <class T>\nstruct rb_tree_value_traits\n{\n  static constexpr bool is_map = mystl::is_pair<T>::value;\n\n  typedef rb_tree_value_traits_imp<T, is_map> value_traits_type;\n\n  typedef typename value_traits_type::key_type    key_type;\n  typedef typename value_traits_type::mapped_type mapped_type;\n  typedef typename value_traits_type::value_type  value_type;\n\n  template <class Ty>\n  static const key_type& get_key(const Ty& value)\n  {\n    return value_traits_type::get_key(value);\n  }\n\n  template <class Ty>\n  static const value_type& get_value(const Ty& value)\n  {\n    return value_traits_type::get_value(value);\n  }\n};\n\n// rb tree node traits\n\ntemplate <class T>\nstruct rb_tree_node_traits\n{\n  typedef rb_tree_color_type                 color_type;\n\n  typedef rb_tree_value_traits<T>            value_traits;\n  typedef typename value_traits::key_type    key_type;\n  typedef typename value_traits::mapped_type mapped_type;\n  typedef typename value_traits::value_type  value_type;\n\n  typedef rb_tree_node_base<T>*              base_ptr;\n  typedef rb_tree_node<T>*                   node_ptr;\n};\n\n// rb tree 的节点设计\n\ntemplate <class T>\nstruct rb_tree_node_base\n{\n  typedef rb_tree_color_type    color_type;\n  typedef rb_tree_node_base<T>* base_ptr;\n  typedef rb_tree_node<T>*      node_ptr;\n\n  base_ptr   parent;  // 父节点\n  base_ptr   left;    // 左子节点\n  base_ptr   right;   // 右子节点\n  color_type color;   // 节点颜色\n\n  base_ptr get_base_ptr()\n  {\n    return &*this;\n  }\n\n  node_ptr get_node_ptr()\n  {\n    return reinterpret_cast<node_ptr>(&*this);\n  }\n\n  node_ptr& get_node_ref()\n  {\n    return reinterpret_cast<node_ptr&>(*this);\n  }\n};\n\ntemplate <class T>\nstruct rb_tree_node :public rb_tree_node_base<T>\n{\n  typedef rb_tree_node_base<T>* base_ptr;\n  typedef rb_tree_node<T>*      node_ptr;\n\n  T value;  // 节点值\n\n  base_ptr get_base_ptr()\n  {\n    return static_cast<base_ptr>(&*this);\n  }\n\n  node_ptr get_node_ptr()\n  {\n    return &*this;\n  }\n};\n\n// rb tree traits\n\ntemplate <class T>\nstruct rb_tree_traits\n{\n  typedef rb_tree_value_traits<T>            value_traits;\n\n  typedef typename value_traits::key_type    key_type;\n  typedef typename value_traits::mapped_type mapped_type;\n  typedef typename value_traits::value_type  value_type;\n\n  typedef value_type*                        pointer;\n  typedef value_type&                        reference;\n  typedef const value_type*                  const_pointer;\n  typedef const value_type&                  const_reference;\n\n  typedef rb_tree_node_base<T>               base_type;\n  typedef rb_tree_node<T>                    node_type;\n\n  typedef base_type*                         base_ptr;\n  typedef node_type*                         node_ptr;\n};\n\n// rb tree 的迭代器设计\n\ntemplate <class T>\nstruct rb_tree_iterator_base :public mystl::iterator<mystl::bidirectional_iterator_tag, T>\n{\n  typedef typename rb_tree_traits<T>::base_ptr  base_ptr;\n\n  base_ptr node;  // 指向节点本身\n\n  rb_tree_iterator_base() :node(nullptr) {}\n\n  // 使迭代器前进\n  void inc()\n  {\n    if (node->right != nullptr)\n    { \n      node = rb_tree_min(node->right);\n    }\n    else\n    {  // 如果没有右子节点\n      auto y = node->parent;\n      while (y->right == node)\n      {\n        node = y;\n        y = y->parent;\n      }\n      if (node->right != y)  // 应对“寻找根节点的下一节点，而根节点没有右子节点”的特殊情况\n        node = y;\n    }\n  }\n\n  // 使迭代器后退\n  void dec()\n  {\n    if (node->parent->parent == node && rb_tree_is_red(node))\n    { // 如果 node 为 header\n      node = node->right;  // 指向整棵树的 max 节点\n    }\n    else if (node->left != nullptr)\n    {\n      node = rb_tree_max(node->left);\n    }\n    else\n    {  // 非 header 节点，也无左子节点\n      auto y = node->parent;\n      while (node == y->left)\n      {\n        node = y;\n        y = y->parent;\n      }\n      node = y;\n    }\n  }\n\n  bool operator==(const rb_tree_iterator_base& rhs) { return node == rhs.node; }\n  bool operator!=(const rb_tree_iterator_base& rhs) { return node != rhs.node; }\n};\n\ntemplate <class T>\nstruct rb_tree_iterator :public rb_tree_iterator_base<T>\n{\n  typedef rb_tree_traits<T>                tree_traits;\n\n  typedef typename tree_traits::value_type value_type;\n  typedef typename tree_traits::pointer    pointer;\n  typedef typename tree_traits::reference  reference;\n  typedef typename tree_traits::base_ptr   base_ptr;\n  typedef typename tree_traits::node_ptr   node_ptr;\n\n  typedef rb_tree_iterator<T>              iterator;\n  typedef rb_tree_const_iterator<T>        const_iterator;\n  typedef iterator                         self;\n\n  using rb_tree_iterator_base<T>::node;\n\n  // 构造函数\n  rb_tree_iterator() {}\n  rb_tree_iterator(base_ptr x) { node = x; }\n  rb_tree_iterator(node_ptr x) { node = x; }\n  rb_tree_iterator(const iterator& rhs) { node = rhs.node; }\n  rb_tree_iterator(const const_iterator& rhs) { node = rhs.node; }\n\n  // 重载操作符\n  reference operator*()  const { return node->get_node_ptr()->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  self& operator++()\n  {\n    this->inc();\n    return *this;\n  }\n  self operator++(int)\n  {\n    self tmp(*this);\n    this->inc();\n    return tmp;\n  }\n  self& operator--()\n  {\n    this->dec();\n    return *this;\n  }\n  self operator--(int)\n  {\n    self tmp(*this);\n    this->dec();\n    return tmp;\n  }\n};\n\ntemplate <class T>\nstruct rb_tree_const_iterator :public rb_tree_iterator_base<T>\n{\n  typedef rb_tree_traits<T>                     tree_traits;\n\n  typedef typename tree_traits::value_type      value_type;\n  typedef typename tree_traits::const_pointer   pointer;\n  typedef typename tree_traits::const_reference reference;\n  typedef typename tree_traits::base_ptr        base_ptr;\n  typedef typename tree_traits::node_ptr        node_ptr;\n\n  typedef rb_tree_iterator<T>                   iterator;\n  typedef rb_tree_const_iterator<T>             const_iterator;\n  typedef const_iterator                        self;\n\n  using rb_tree_iterator_base<T>::node;\n\n  // 构造函数\n  rb_tree_const_iterator() {}\n  rb_tree_const_iterator(base_ptr x) { node = x; }\n  rb_tree_const_iterator(node_ptr x) { node = x; }\n  rb_tree_const_iterator(const iterator& rhs) { node = rhs.node; }\n  rb_tree_const_iterator(const const_iterator& rhs) { node = rhs.node; }\n\n  // 重载操作符\n  reference operator*()  const { return node->get_node_ptr()->value; }\n  pointer   operator->() const { return &(operator*()); }\n\n  self& operator++()\n  {\n    this->inc();\n    return *this;\n  }\n  self operator++(int)\n  {\n    self tmp(*this);\n    this->inc();\n    return tmp;\n  }\n  self& operator--()\n  {\n    this->dec();\n    return *this;\n  }\n  self operator--(int)\n  {\n    self tmp(*this);\n    this->dec();\n    return tmp;\n  }\n};\n\n// tree algorithm\n\ntemplate <class NodePtr>\nNodePtr rb_tree_min(NodePtr x) noexcept\n{\n  while (x->left != nullptr)\n    x = x->left;\n  return x;\n}\n\ntemplate <class NodePtr>\nNodePtr rb_tree_max(NodePtr x) noexcept\n{\n  while (x->right != nullptr)\n    x = x->right;\n  return x;\n}\n\ntemplate <class NodePtr>\nbool rb_tree_is_lchild(NodePtr node) noexcept\n{\n  return node == node->parent->left;\n}\n\ntemplate <class NodePtr>\nbool rb_tree_is_red(NodePtr node) noexcept\n{\n  return node->color == rb_tree_red;\n}\n\ntemplate <class NodePtr>\nvoid rb_tree_set_black(NodePtr& node) noexcept\n{\n  node->color = rb_tree_black;\n}\n\ntemplate <class NodePtr>\nvoid rb_tree_set_red(NodePtr& node) noexcept\n{\n  node->color = rb_tree_red;\n}\n\ntemplate <class NodePtr>\nNodePtr rb_tree_next(NodePtr node) noexcept\n{\n  if (node->right != nullptr)\n    return rb_tree_min(node->right);\n  while (!rb_tree_is_lchild(node))\n    node = node->parent;\n  return node->parent;\n}\n\n/*---------------------------------------*\\\n|       p                         p       |\n|      / \\                       / \\      |\n|     x   d    rotate left      y   d     |\n|    / \\       ===========>    / \\        |\n|   a   y                     x   c       |\n|      / \\                   / \\          |\n|     b   c                 a   b         |\n\\*---------------------------------------*/\n// 左旋，参数一为左旋点，参数二为根节点\ntemplate <class NodePtr>\nvoid rb_tree_rotate_left(NodePtr x, NodePtr& root) noexcept\n{\n  auto y = x->right;  // y 为 x 的右子节点\n  x->right = y->left;\n  if (y->left != nullptr)\n    y->left->parent = x;\n  y->parent = x->parent;\n\n  if (x == root)\n  { // 如果 x 为根节点，让 y 顶替 x 成为根节点\n    root = y;\n  }\n  else if (rb_tree_is_lchild(x))\n  { // 如果 x 是左子节点\n    x->parent->left = y;\n  }\n  else\n  { // 如果 x 是右子节点\n    x->parent->right = y;\n  }\n  // 调整 x 与 y 的关系\n  y->left = x;  \n  x->parent = y;\n}\n\n/*----------------------------------------*\\\n|     p                         p          |\n|    / \\                       / \\         |\n|   d   x      rotate right   d   y        |\n|      / \\     ===========>      / \\       |\n|     y   a                     b   x      |\n|    / \\                           / \\     |\n|   b   c                         c   a    |\n\\*----------------------------------------*/\n// 右旋，参数一为右旋点，参数二为根节点\ntemplate <class NodePtr>\nvoid rb_tree_rotate_right(NodePtr x, NodePtr& root) noexcept\n{\n  auto y = x->left;\n  x->left = y->right;\n  if (y->right)\n    y->right->parent = x;\n  y->parent = x->parent;\n\n  if (x == root)\n  { // 如果 x 为根节点，让 y 顶替 x 成为根节点\n    root = y;\n  }\n  else if (rb_tree_is_lchild(x))\n  { // 如果 x 是右子节点\n    x->parent->left = y;\n  }\n  else\n  { // 如果 x 是左子节点\n    x->parent->right = y;\n  }\n  // 调整 x 与 y 的关系\n  y->right = x;                      \n  x->parent = y;\n}\n\n// 插入节点后使 rb tree 重新平衡，参数一为新增节点，参数二为根节点\n//\n// case 1: 新增节点位于根节点，令新增节点为黑\n// case 2: 新增节点的父节点为黑，没有破坏平衡，直接返回\n// case 3: 父节点和叔叔节点都为红，令父节点和叔叔节点为黑，祖父节点为红，\n//         然后令祖父节点为当前节点，继续处理\n// case 4: 父节点为红，叔叔节点为 NIL 或黑色，父节点为左（右）孩子，当前节点为右（左）孩子，\n//         让父节点成为当前节点，再以当前节点为支点左（右）旋\n// case 5: 父节点为红，叔叔节点为 NIL 或黑色，父节点为左（右）孩子，当前节点为左（右）孩子，\n//         让父节点变为黑色，祖父节点变为红色，以祖父节点为支点右（左）旋\n//\n// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630\n//          http://blog.csdn.net/v_JULY_v/article/details/6109153\ntemplate <class NodePtr>\nvoid rb_tree_insert_rebalance(NodePtr x, NodePtr& root) noexcept\n{\n  rb_tree_set_red(x);  // 新增节点为红色\n  while (x != root && rb_tree_is_red(x->parent))\n  {\n    if (rb_tree_is_lchild(x->parent))\n    { // 如果父节点是左子节点\n      auto uncle = x->parent->parent->right;\n      if (uncle != nullptr && rb_tree_is_red(uncle))\n      { // case 3: 父节点和叔叔节点都为红\n        rb_tree_set_black(x->parent);\n        rb_tree_set_black(uncle);\n        x = x->parent->parent;\n        rb_tree_set_red(x);\n      }\n      else\n      { // 无叔叔节点或叔叔节点为黑\n        if (!rb_tree_is_lchild(x))\n        { // case 4: 当前节点 x 为右子节点\n          x = x->parent;\n          rb_tree_rotate_left(x, root);\n        }\n        // 都转换成 case 5： 当前节点为左子节点\n        rb_tree_set_black(x->parent);\n        rb_tree_set_red(x->parent->parent);\n        rb_tree_rotate_right(x->parent->parent, root);\n        break;\n      }\n    }\n    else  // 如果父节点是右子节点，对称处理\n    { \n      auto uncle = x->parent->parent->left;\n      if (uncle != nullptr && rb_tree_is_red(uncle))\n      { // case 3: 父节点和叔叔节点都为红\n        rb_tree_set_black(x->parent);\n        rb_tree_set_black(uncle);\n        x = x->parent->parent;\n        rb_tree_set_red(x);\n        // 此时祖父节点为红，可能会破坏红黑树的性质，令当前节点为祖父节点，继续处理\n      }\n      else\n      { // 无叔叔节点或叔叔节点为黑\n        if (rb_tree_is_lchild(x))\n        { // case 4: 当前节点 x 为左子节点\n          x = x->parent;\n          rb_tree_rotate_right(x, root);\n        }\n        // 都转换成 case 5： 当前节点为左子节点\n        rb_tree_set_black(x->parent);\n        rb_tree_set_red(x->parent->parent);\n        rb_tree_rotate_left(x->parent->parent, root);\n        break;\n      }\n    }\n  }\n  rb_tree_set_black(root);  // 根节点永远为黑\n}\n\n// 删除节点后使 rb tree 重新平衡，参数一为要删除的节点，参数二为根节点，参数三为最小节点，参数四为最大节点\n// \n// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630\n//          http://blog.csdn.net/v_JULY_v/article/details/6109153\ntemplate <class NodePtr>\nNodePtr rb_tree_erase_rebalance(NodePtr z, NodePtr& root, NodePtr& leftmost, NodePtr& rightmost)\n{\n  // y 是可能的替换节点，指向最终要删除的节点\n  auto y = (z->left == nullptr || z->right == nullptr) ? z : rb_tree_next(z);\n  // x 是 y 的一个独子节点或 NIL 节点\n  auto x = y->left != nullptr ? y->left : y->right;\n  // xp 为 x 的父节点\n  NodePtr xp = nullptr;\n\n  // y != z 说明 z 有两个非空子节点，此时 y 指向 z 右子树的最左节点，x 指向 y 的右子节点。\n  // 用 y 顶替 z 的位置，用 x 顶替 y 的位置，最后用 y 指向 z\n  if (y != z)\n  {\n    z->left->parent = y;\n    y->left = z->left;\n\n    // 如果 y 不是 z 的右子节点，那么 z 的右子节点一定有左孩子\n    if (y != z->right)\n    { // x 替换 y 的位置\n      xp = y->parent;\n      if (x != nullptr)\n        x->parent = y->parent;\n\n      y->parent->left = x;\n      y->right = z->right;\n      z->right->parent = y;\n    }\n    else\n    {\n      xp = y;\n    }\n\n    // 连接 y 与 z 的父节点 \n    if (root == z)\n      root = y;\n    else if (rb_tree_is_lchild(z))\n      z->parent->left = y;\n    else\n      z->parent->right = y;\n    y->parent = z->parent;\n    mystl::swap(y->color, z->color);\n    y = z;\n  }\n  // y == z 说明 z 至多只有一个孩子\n  else\n  { \n    xp = y->parent;\n    if (x)  \n      x->parent = y->parent;\n\n    // 连接 x 与 z 的父节点\n    if (root == z)\n      root = x;\n    else if (rb_tree_is_lchild(z))\n      z->parent->left = x;\n    else\n      z->parent->right = x;\n\n    // 此时 z 有可能是最左节点或最右节点，更新数据\n    if (leftmost == z)\n      leftmost = x == nullptr ? xp : rb_tree_min(x);\n    if (rightmost == z)\n      rightmost = x == nullptr ? xp : rb_tree_max(x);\n  }\n\n  // 此时，y 指向要删除的节点，x 为替代节点，从 x 节点开始调整。\n  // 如果删除的节点为红色，树的性质没有被破坏，否则按照以下情况调整（x 为左子节点为例）：\n  // case 1: 兄弟节点为红色，令父节点为红，兄弟节点为黑，进行左（右）旋，继续处理\n  // case 2: 兄弟节点为黑色，且两个子节点都为黑色或 NIL，令兄弟节点为红，父节点成为当前节点，继续处理\n  // case 3: 兄弟节点为黑色，左子节点为红色或 NIL，右子节点为黑色或 NIL，\n  //         令兄弟节点为红，兄弟节点的左子节点为黑，以兄弟节点为支点右（左）旋，继续处理\n  // case 4: 兄弟节点为黑色，右子节点为红色，令兄弟节点为父节点的颜色，父节点为黑色，兄弟节点的右子节点\n  //         为黑色，以父节点为支点左（右）旋，树的性质调整完成，算法结束\n  if (!rb_tree_is_red(y))\n  { // x 为黑色时，调整，否则直接将 x 变为黑色即可\n    while (x != root && (x == nullptr || !rb_tree_is_red(x)))\n    {\n      if (x == xp->left)\n      { // 如果 x 为左子节点\n        auto brother = xp->right;\n        if (rb_tree_is_red(brother))\n        { // case 1\n          rb_tree_set_black(brother);\n          rb_tree_set_red(xp);\n          rb_tree_rotate_left(xp, root);\n          brother = xp->right;\n        }\n        // case 1 转为为了 case 2、3、4 中的一种\n        if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) &&\n            (brother->right == nullptr || !rb_tree_is_red(brother->right)))\n        { // case 2\n          rb_tree_set_red(brother);\n          x = xp;\n          xp = xp->parent;\n        }\n        else\n        { \n          if (brother->right == nullptr || !rb_tree_is_red(brother->right))\n          { // case 3\n            if (brother->left != nullptr)\n              rb_tree_set_black(brother->left);\n            rb_tree_set_red(brother);\n            rb_tree_rotate_right(brother, root);\n            brother = xp->right;\n          }\n          // 转为 case 4\n          brother->color = xp->color;\n          rb_tree_set_black(xp);\n          if (brother->right != nullptr)  \n            rb_tree_set_black(brother->right);\n          rb_tree_rotate_left(xp, root);\n          break;\n        }\n      }\n      else  // x 为右子节点，对称处理\n      { \n        auto brother = xp->left;\n        if (rb_tree_is_red(brother))\n        { // case 1\n          rb_tree_set_black(brother);\n          rb_tree_set_red(xp);\n          rb_tree_rotate_right(xp, root);\n          brother = xp->left;\n        }\n        if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) &&\n            (brother->right == nullptr || !rb_tree_is_red(brother->right)))\n        { // case 2\n          rb_tree_set_red(brother);\n          x = xp;\n          xp = xp->parent;\n        }\n        else\n        {\n          if (brother->left == nullptr || !rb_tree_is_red(brother->left))\n          { // case 3\n            if (brother->right != nullptr)\n              rb_tree_set_black(brother->right);\n            rb_tree_set_red(brother);\n            rb_tree_rotate_left(brother, root);\n            brother = xp->left;\n          }\n          // 转为 case 4\n          brother->color = xp->color;\n          rb_tree_set_black(xp);\n          if (brother->left != nullptr)  \n            rb_tree_set_black(brother->left);\n          rb_tree_rotate_right(xp, root);\n          break;\n        }\n      }\n    }\n    if (x != nullptr)\n      rb_tree_set_black(x);\n  }\n  return y;\n}\n\n// 模板类 rb_tree\n// 参数一代表数据类型，参数二代表键值比较类型\ntemplate <class T, class Compare>\nclass rb_tree\n{\npublic:\n  // rb_tree 的嵌套型别定义 \n  \n  typedef rb_tree_traits<T>                        tree_traits;\n  typedef rb_tree_value_traits<T>                  value_traits;\n\n  typedef typename tree_traits::base_type          base_type;\n  typedef typename tree_traits::base_ptr           base_ptr;\n  typedef typename tree_traits::node_type          node_type;\n  typedef typename tree_traits::node_ptr           node_ptr;\n  typedef typename tree_traits::key_type           key_type;\n  typedef typename tree_traits::mapped_type        mapped_type;\n  typedef typename tree_traits::value_type         value_type;\n  typedef Compare                                  key_compare;\n\n  typedef mystl::allocator<T>                      allocator_type;\n  typedef mystl::allocator<T>                      data_allocator;\n  typedef mystl::allocator<base_type>              base_allocator;\n  typedef mystl::allocator<node_type>              node_allocator;\n\n  typedef typename allocator_type::pointer         pointer;\n  typedef typename allocator_type::const_pointer   const_pointer;\n  typedef typename allocator_type::reference       reference;\n  typedef typename allocator_type::const_reference const_reference;\n  typedef typename allocator_type::size_type       size_type;\n  typedef typename allocator_type::difference_type difference_type;\n\n  typedef rb_tree_iterator<T>                      iterator;\n  typedef rb_tree_const_iterator<T>                const_iterator;\n  typedef mystl::reverse_iterator<iterator>        reverse_iterator;\n  typedef mystl::reverse_iterator<const_iterator>  const_reverse_iterator;\n\n  allocator_type get_allocator() const { return node_allocator(); }\n  key_compare    key_comp()      const { return key_comp_; }\n\nprivate:\n  // 用以下三个数据表现 rb tree\n  base_ptr    header_;      // 特殊节点，与根节点互为对方的父节点\n  size_type   node_count_;  // 节点数\n  key_compare key_comp_;    // 节点键值比较的准则\n\nprivate:\n  // 以下三个函数用于取得根节点，最小节点和最大节点\n  base_ptr& root()      const { return header_->parent; }\n  base_ptr& leftmost()  const { return header_->left; }\n  base_ptr& rightmost() const { return header_->right; }\n\npublic:\n  // 构造、复制、析构函数\n  rb_tree() { rb_tree_init(); }\n\n  rb_tree(const rb_tree& rhs);\n  rb_tree(rb_tree&& rhs) noexcept;\n\n  rb_tree& operator=(const rb_tree& rhs);\n  rb_tree& operator=(rb_tree&& rhs);\n\n  ~rb_tree() { clear(); }\n\npublic:\n  // 迭代器相关操作\n\n  iterator               begin()         noexcept \n  { return leftmost(); }\n  const_iterator         begin()   const noexcept\n  { return leftmost(); }\n  iterator               end()           noexcept\n  { return header_; }\n  const_iterator         end()     const noexcept\n  { return header_; }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return const_reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return const_reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关操作\n\n  bool      empty()    const noexcept { return node_count_ == 0; }\n  size_type size()     const noexcept { return node_count_; }\n  size_type max_size() const noexcept { return static_cast<size_type>(-1); }\n\n  // 插入删除相关操作\n\n  // emplace\n\n  template <class ...Args>\n  iterator  emplace_multi(Args&& ...args);\n\n  template <class ...Args>\n  mystl::pair<iterator, bool> emplace_unique(Args&& ...args);\n\n  template <class ...Args>\n  iterator  emplace_multi_use_hint(iterator hint, Args&& ...args);\n\n  template <class ...Args>\n  iterator  emplace_unique_use_hint(iterator hint, Args&& ...args);\n\n  // insert\n\n  iterator  insert_multi(const value_type& value);\n  iterator  insert_multi(value_type&& value)\n  {\n    return emplace_multi(mystl::move(value));\n  }\n\n  iterator  insert_multi(iterator hint, const value_type& value)\n  {\n    return emplace_multi_use_hint(hint, value);\n  }\n  iterator  insert_multi(iterator hint, value_type&& value)\n  {\n    return emplace_multi_use_hint(hint, mystl::move(value));\n  }\n\n  template <class InputIterator>\n  void      insert_multi(InputIterator first, InputIterator last)\n  {\n    size_type n = mystl::distance(first, last);\n    THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, \"rb_tree<T, Comp>'s size too big\");\n    for (; n > 0; --n, ++first)\n      insert_multi(end(), *first);\n  }\n\n  mystl::pair<iterator, bool> insert_unique(const value_type& value);\n  mystl::pair<iterator, bool> insert_unique(value_type&& value)\n  {\n    return emplace_unique(mystl::move(value));\n  }\n\n  iterator  insert_unique(iterator hint, const value_type& value)\n  {\n    return emplace_unique_use_hint(hint, value);\n  }\n  iterator  insert_unique(iterator hint, value_type&& value)\n  {\n    return emplace_unique_use_hint(hint, mystl::move(value));\n  }\n\n  template <class InputIterator>\n  void      insert_unique(InputIterator first, InputIterator last)\n  {\n    size_type n = mystl::distance(first, last);\n    THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, \"rb_tree<T, Comp>'s size too big\");\n    for (; n > 0; --n, ++first)\n      insert_unique(end(), *first);\n  }\n\n  // erase\n\n  iterator  erase(iterator hint);\n\n  size_type erase_multi(const key_type& key);\n  size_type erase_unique(const key_type& key);\n\n  void      erase(iterator first, iterator last);\n\n  void      clear();\n\n  // rb_tree 相关操作\n\n  iterator       find(const key_type& key);\n  const_iterator find(const key_type& key) const;\n\n  size_type      count_multi(const key_type& key) const\n  {\n    auto p = equal_range_multi(key);\n    return static_cast<size_type>(mystl::distance(p.first, p.second));\n  }\n  size_type      count_unique(const key_type& key) const\n  {\n    return find(key) != end() ? 1 : 0;\n  }\n\n  iterator       lower_bound(const key_type& key);\n  const_iterator lower_bound(const key_type& key) const;\n\n  iterator       upper_bound(const key_type& key);\n  const_iterator upper_bound(const key_type& key) const;\n\n  mystl::pair<iterator, iterator>             \n  equal_range_multi(const key_type& key)\n  {\n    return mystl::pair<iterator, iterator>(lower_bound(key), upper_bound(key));\n  }\n  mystl::pair<const_iterator, const_iterator>\n  equal_range_multi(const key_type& key) const\n  {\n    return mystl::pair<const_iterator, const_iterator>(lower_bound(key), upper_bound(key));\n  }\n\n  mystl::pair<iterator, iterator>             \n  equal_range_unique(const key_type& key)\n  {\n    iterator it = find(key);\n    auto next = it;\n    return it == end() ? mystl::make_pair(it, it) : mystl::make_pair(it, ++next);\n  }\n  mystl::pair<const_iterator, const_iterator> \n  equal_range_unique(const key_type& key) const\n  {\n    const_iterator it = find(key);\n    auto next = it;\n    return it == end() ? mystl::make_pair(it, it) : mystl::make_pair(it, ++next);\n  }\n\n  void swap(rb_tree& rhs) noexcept;\n\nprivate:\n\n  // node related\n  template <class ...Args>\n  node_ptr create_node(Args&&... args);\n  node_ptr clone_node(base_ptr x);\n  void     destroy_node(node_ptr p);\n\n  // init / reset\n  void     rb_tree_init();\n  void     reset();\n\n  // get insert pos\n  mystl::pair<base_ptr, bool> \n           get_insert_multi_pos(const key_type& key);\n  mystl::pair<mystl::pair<base_ptr, bool>, bool> \n           get_insert_unique_pos(const key_type& key);\n\n  // insert value / insert node\n  iterator insert_value_at(base_ptr x, const value_type& value, bool add_to_left);\n  iterator insert_node_at(base_ptr x, node_ptr node, bool add_to_left);\n\n  // insert use hint\n  iterator insert_multi_use_hint(iterator hint, key_type key, node_ptr node);\n  iterator insert_unique_use_hint(iterator hint, key_type key, node_ptr node);\n\n  // copy tree / erase tree\n  base_ptr copy_from(base_ptr x, base_ptr p);\n  void     erase_since(base_ptr x);\n};\n\n/*****************************************************************************************/\n\n// 复制构造函数\ntemplate <class T, class Compare>\nrb_tree<T, Compare>::\nrb_tree(const rb_tree& rhs)\n{\n  rb_tree_init();\n  if (rhs.node_count_ != 0)\n  {\n    root() = copy_from(rhs.root(), header_);\n    leftmost() = rb_tree_min(root());\n    rightmost() = rb_tree_max(root());\n  }\n  node_count_ = rhs.node_count_;\n  key_comp_ = rhs.key_comp_;\n}\n\n// 移动构造函数\ntemplate <class T, class Compare>\nrb_tree<T, Compare>::\nrb_tree(rb_tree&& rhs) noexcept\n  :header_(mystl::move(rhs.header_)),\n  node_count_(rhs.node_count_),\n  key_comp_(rhs.key_comp_)\n{\n  rhs.reset();\n}\n\n// 复制赋值操作符\ntemplate <class T, class Compare>\nrb_tree<T, Compare>& \nrb_tree<T, Compare>::\noperator=(const rb_tree& rhs)\n{\n  if (this != &rhs)\n  {\n    clear();\n\n    if (rhs.node_count_ != 0)\n    {\n      root() = copy_from(rhs.root(), header_);\n      leftmost() = rb_tree_min(root());\n      rightmost() = rb_tree_max(root());\n    }\n\n    node_count_ = rhs.node_count_;\n    key_comp_ = rhs.key_comp_;\n  }\n  return *this;\n}\n\n// 移动赋值操作符\ntemplate <class T, class Compare>\nrb_tree<T, Compare>&\nrb_tree<T, Compare>::\noperator=(rb_tree&& rhs)\n{\n  clear();\n  header_ = mystl::move(rhs.header_);\n  node_count_ = rhs.node_count_;\n  key_comp_ = rhs.key_comp_;\n  rhs.reset();\n  return *this;\n}\n\n// 就地插入元素，键值允许重复\ntemplate <class T, class Compare>\ntemplate <class ...Args>\ntypename rb_tree<T, Compare>::iterator \nrb_tree<T, Compare>::\nemplace_multi(Args&& ...args)\n{\n  THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, \"rb_tree<T, Comp>'s size too big\");\n  node_ptr np = create_node(mystl::forward<Args>(args)...);\n  auto res = get_insert_multi_pos(value_traits::get_key(np->value));\n  return insert_node_at(res.first, np, res.second);\n}\n\n// 就地插入元素，键值不允许重复\ntemplate <class T, class Compare>\ntemplate <class ...Args>\nmystl::pair<typename rb_tree<T, Compare>::iterator, bool> \nrb_tree<T, Compare>::\nemplace_unique(Args&& ...args)\n{\n  THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, \"rb_tree<T, Comp>'s size too big\");\n  node_ptr np = create_node(mystl::forward<Args>(args)...);\n  auto res = get_insert_unique_pos(value_traits::get_key(np->value));\n  if (res.second)\n  { // 插入成功\n    return mystl::make_pair(insert_node_at(res.first.first, np, res.first.second), true);\n  }\n  destroy_node(np);\n  return mystl::make_pair(iterator(res.first.first), false);\n}\n\n// 就地插入元素，键值允许重复，当 hint 位置与插入位置接近时，插入操作的时间复杂度可以降低\ntemplate <class T, class Compare>\ntemplate <class ...Args>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\nemplace_multi_use_hint(iterator hint, Args&& ...args)\n{\n  THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, \"rb_tree<T, Comp>'s size too big\");\n  node_ptr np = create_node(mystl::forward<Args>(args)...);\n  if (node_count_ == 0)\n  {\n    return insert_node_at(header_, np, true);\n  }\n  key_type key = value_traits::get_key(np->value);\n  if (hint == begin())\n  { // 位于 begin 处\n    if (key_comp_(key, value_traits::get_key(*hint)))\n    {\n      return insert_node_at(hint.node, np, true);\n    }\n    else\n    {\n      auto pos = get_insert_multi_pos(key);\n      return insert_node_at(pos.first, np, pos.second);\n    }\n  }\n  else if (hint == end())\n  { // 位于 end 处\n    if (!key_comp_(key, value_traits::get_key(rightmost()->get_node_ptr()->value)))\n    {\n      return insert_node_at(rightmost(), np, false);\n    }\n    else\n    {\n      auto pos = get_insert_multi_pos(key);\n      return insert_node_at(pos.first, np, pos.second);\n    }\n  }\n  return insert_multi_use_hint(hint, key, np);\n}\n\n// 就地插入元素，键值不允许重复，当 hint 位置与插入位置接近时，插入操作的时间复杂度可以降低\ntemplate<class T, class Compare>\ntemplate<class ...Args>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\nemplace_unique_use_hint(iterator hint, Args&& ...args)\n{\n  THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, \"rb_tree<T, Comp>'s size too big\");\n  node_ptr np = create_node(mystl::forward<Args>(args)...);\n  if (node_count_ == 0)\n  {\n    return insert_node_at(header_, np, true);\n  }\n  key_type key = value_traits::get_key(np->value);\n  if (hint == begin())\n  { // 位于 begin 处\n    if (key_comp_(key, value_traits::get_key(*hint)))\n    {\n      return insert_node_at(hint.node, np, true);\n    }\n    else\n    {\n      auto pos = get_insert_unique_pos(key);\n      if (!pos.second)\n      {\n        destroy_node(np);\n        return pos.first.first;\n      }\n      return insert_node_at(pos.first.first, np, pos.first.second);\n    }\n  }\n  else if (hint == end())\n  { // 位于 end 处\n    if (key_comp_(value_traits::get_key(rightmost()->get_node_ptr()->value), key))\n    {\n      return insert_node_at(rightmost(), np, false);\n    }\n    else\n    {\n      auto pos = get_insert_unique_pos(key);\n      if (!pos.second)\n      {\n        destroy_node(np);\n        return pos.first.first;\n      }\n      return insert_node_at(pos.first.first, np, pos.first.second);\n    }\n  }\n  return insert_unique_use_hint(hint, key, np);\n}\n\n// 插入元素，节点键值允许重复\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\ninsert_multi(const value_type& value)\n{\n  THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, \"rb_tree<T, Comp>'s size too big\");\n  auto res = get_insert_multi_pos(value_traits::get_key(value));\n  return insert_value_at(res.first, value, res.second);\n}\n\n// 插入新值，节点键值不允许重复，返回一个 pair，若插入成功，pair 的第二参数为 true，否则为 false\ntemplate <class T, class Compare>\nmystl::pair<typename rb_tree<T, Compare>::iterator, bool>\nrb_tree<T, Compare>::\ninsert_unique(const value_type& value)\n{\n  THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, \"rb_tree<T, Comp>'s size too big\");\n  auto res = get_insert_unique_pos(value_traits::get_key(value));\n  if (res.second)\n  { // 插入成功\n    return mystl::make_pair(insert_value_at(res.first.first, value, res.first.second), true);\n  }\n  return mystl::make_pair(res.first.first, false);\n}\n\n// 删除 hint 位置的节点\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\nerase(iterator hint)\n{\n  auto node = hint.node->get_node_ptr();\n  iterator next(node);\n  ++next;\n  \n  rb_tree_erase_rebalance(hint.node, root(), leftmost(), rightmost());\n  destroy_node(node);\n  --node_count_;\n  return next;\n}\n\n// 删除键值等于 key 的元素，返回删除的个数\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::size_type\nrb_tree<T, Compare>::\nerase_multi(const key_type& key)\n{\n  auto p = equal_range_multi(key);\n  size_type n = mystl::distance(p.first, p.second);\n  erase(p.first, p.second);\n  return n;\n}\n\n// 删除键值等于 key 的元素，返回删除的个数\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::size_type\nrb_tree<T, Compare>::\nerase_unique(const key_type& key)\n{\n  auto it = find(key);\n  if (it != end())\n  {\n    erase(it);\n    return 1;\n  }\n  return 0;\n}\n\n// 删除[first, last)区间内的元素\ntemplate <class T, class Compare>\nvoid rb_tree<T, Compare>::\nerase(iterator first, iterator last)\n{\n  if (first == begin() && last == end())\n  {\n    clear();\n  }\n  else\n  {\n    while (first != last)\n      erase(first++);\n  }\n}\n\n// 清空 rb tree\ntemplate <class T, class Compare>\nvoid rb_tree<T, Compare>::\nclear()\n{\n  if (node_count_ != 0)\n  {\n    erase_since(root());\n    leftmost() = header_;\n    root() = nullptr;\n    rightmost() = header_;\n    node_count_ = 0;\n  }\n}\n\n// 查找键值为 k 的节点，返回指向它的迭代器\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\nfind(const key_type& key)\n{\n  auto y = header_;  // 最后一个不小于 key 的节点\n  auto x = root();\n  while (x != nullptr)\n  {\n    if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key))\n    { // key 小于等于 x 键值，向左走\n      y = x, x = x->left;\n    }\n    else\n    { // key 大于 x 键值，向右走\n      x = x->right;\n    }\n  }\n  iterator j = iterator(y);\n  return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() : j;\n}\n\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::const_iterator\nrb_tree<T, Compare>::\nfind(const key_type& key) const\n{\n  auto y = header_;  // 最后一个不小于 key 的节点\n  auto x = root();\n  while (x != nullptr)\n  {\n    if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key))\n    { // key 小于等于 x 键值，向左走\n      y = x, x = x->left;\n    }\n    else\n    { // key 大于 x 键值，向右走\n      x = x->right;\n    }\n  }\n  const_iterator j = const_iterator(y);\n  return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() : j;\n}\n\n// 键值不小于 key 的第一个位置\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\nlower_bound(const key_type& key)\n{\n  auto y = header_;\n  auto x = root();\n  while (x != nullptr)\n  {\n    if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key))\n    { // key <= x\n      y = x, x = x->left;\n    }\n    else\n    {\n      x = x->right;\n    }\n  }\n  return iterator(y);\n}\n\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::const_iterator\nrb_tree<T, Compare>::\nlower_bound(const key_type& key) const\n{\n  auto y = header_;\n  auto x = root();\n  while (x != nullptr)\n  {\n    if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key))\n    { // key <= x\n      y = x, x = x->left;\n    }\n    else\n    {\n      x = x->right;\n    }\n  }\n  return const_iterator(y);\n}\n\n// 键值不小于 key 的最后一个位置\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\nupper_bound(const key_type& key)\n{\n  auto y = header_;\n  auto x = root();\n  while (x != nullptr)\n  {\n    if (key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)))\n    { // key < x\n      y = x, x = x->left;\n    }\n    else\n    {\n      x = x->right;\n    }\n  }\n  return iterator(y);\n}\n\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::const_iterator\nrb_tree<T, Compare>::\nupper_bound(const key_type& key) const\n{\n  auto y = header_;\n  auto x = root();\n  while (x != nullptr)\n  {\n    if (key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)))\n    { // key < x\n      y = x, x = x->left;\n    }\n    else\n    {\n      x = x->right;\n    }\n  }\n  return const_iterator(y);\n}\n\n// 交换 rb tree\ntemplate <class T, class Compare>\nvoid rb_tree<T, Compare>::\nswap(rb_tree& rhs) noexcept\n{\n  if (this != &rhs)\n  {\n    mystl::swap(header_, rhs.header_);\n    mystl::swap(node_count_, rhs.node_count_);\n    mystl::swap(key_comp_, rhs.key_comp_);\n  }\n}\n\n/*****************************************************************************************/\n// helper function\n\n// 创建一个结点\ntemplate <class T, class Compare>\ntemplate <class ...Args>\ntypename rb_tree<T, Compare>::node_ptr\nrb_tree<T, Compare>::\ncreate_node(Args&&... args)\n{\n  auto tmp = node_allocator::allocate(1);\n  try\n  {\n    data_allocator::construct(mystl::address_of(tmp->value), mystl::forward<Args>(args)...);\n    tmp->left = nullptr;\n    tmp->right = nullptr;\n    tmp->parent = nullptr;\n  }\n  catch (...)\n  {\n    node_allocator::deallocate(tmp);\n    throw;\n  }\n  return tmp;\n}\n\n// 复制一个结点\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::node_ptr\nrb_tree<T, Compare>::\nclone_node(base_ptr x)\n{\n  node_ptr tmp = create_node(x->get_node_ptr()->value);\n  tmp->color = x->color;\n  tmp->left = nullptr;\n  tmp->right = nullptr;\n  return tmp;\n}\n\n// 销毁一个结点\ntemplate <class T, class Compare>\nvoid rb_tree<T, Compare>::\ndestroy_node(node_ptr p)\n{\n  data_allocator::destroy(&p->value);\n  node_allocator::deallocate(p);\n}\n\n// 初始化容器\ntemplate <class T, class Compare>\nvoid rb_tree<T, Compare>::\nrb_tree_init()\n{\n  header_ = base_allocator::allocate(1);\n  header_->color = rb_tree_red;  // header_ 节点颜色为红，与 root 区分\n  root() = nullptr;\n  leftmost() = header_;\n  rightmost() = header_;\n  node_count_ = 0;\n}\n\n// reset 函数\ntemplate <class T, class Compare>\nvoid rb_tree<T, Compare>::reset()\n{\n  header_ = nullptr;\n  node_count_ = 0;\n}\n\n// get_insert_multi_pos 函数\ntemplate <class T, class Compare>\nmystl::pair<typename rb_tree<T, Compare>::base_ptr, bool>\nrb_tree<T, Compare>::get_insert_multi_pos(const key_type& key)\n{\n  auto x = root();\n  auto y = header_;\n  bool add_to_left = true;\n  while (x != nullptr)\n  {\n    y = x;\n    add_to_left = key_comp_(key, value_traits::get_key(x->get_node_ptr()->value));\n    x = add_to_left ? x->left : x->right;\n  }\n  return mystl::make_pair(y, add_to_left);\n}\n\n// get_insert_unique_pos 函数\ntemplate <class T, class Compare>\nmystl::pair<mystl::pair<typename rb_tree<T, Compare>::base_ptr, bool>, bool>\nrb_tree<T, Compare>::get_insert_unique_pos(const key_type& key)\n{ // 返回一个 pair，第一个值为一个 pair，包含插入点的父节点和一个 bool 表示是否在左边插入，\n  // 第二个值为一个 bool，表示是否插入成功\n  auto x = root();\n  auto y = header_;\n  bool add_to_left = true;  // 树为空时也在 header_ 左边插入\n  while (x != nullptr)\n  {\n    y = x;\n    add_to_left = key_comp_(key, value_traits::get_key(x->get_node_ptr()->value));\n    x = add_to_left ? x->left : x->right;\n  }\n  iterator j = iterator(y);  // 此时 y 为插入点的父节点\n  if (add_to_left)\n  {\n    if (y == header_ || j == begin())\n    { // 如果树为空树或插入点在最左节点处，肯定可以插入新的节点\n      return mystl::make_pair(mystl::make_pair(y, true), true);\n    }\n    else\n    { // 否则，如果存在重复节点，那么 --j 就是重复的值\n      --j;\n    }\n  }\n  if (key_comp_(value_traits::get_key(*j), key))  \n  { // 表明新节点没有重复\n    return mystl::make_pair(mystl::make_pair(y, add_to_left), true);\n  }\n  // 进行至此，表示新节点与现有节点键值重复\n  return mystl::make_pair(mystl::make_pair(y, add_to_left), false);\n}\n\n// insert_value_at 函数\n// x 为插入点的父节点， value 为要插入的值，add_to_left 表示是否在左边插入\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\ninsert_value_at(base_ptr x, const value_type& value, bool add_to_left)\n{\n  node_ptr node = create_node(value);\n  node->parent = x;\n  auto base_node = node->get_base_ptr();\n  if (x == header_)\n  {\n    root() = base_node;\n    leftmost() = base_node;\n    rightmost() = base_node;\n  }\n  else if (add_to_left)\n  {\n    x->left = base_node;\n    if (leftmost() == x)\n      leftmost() = base_node;\n  }\n  else\n  {\n    x->right = base_node;\n    if (rightmost() == x)\n      rightmost() = base_node;\n  }\n  rb_tree_insert_rebalance(base_node, root());\n  ++node_count_;\n  return iterator(node);\n}\n\n// 在 x 节点处插入新的节点\n// x 为插入点的父节点， node 为要插入的节点，add_to_left 表示是否在左边插入\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator\nrb_tree<T, Compare>::\ninsert_node_at(base_ptr x, node_ptr node, bool add_to_left)\n{\n  node->parent = x;\n  auto base_node = node->get_base_ptr();\n  if (x == header_)\n  {\n    root() = base_node;\n    leftmost() = base_node;\n    rightmost() = base_node;\n  }\n  else if (add_to_left)\n  {\n    x->left = base_node;\n    if (leftmost() == x)\n      leftmost() = base_node;\n  }\n  else\n  {\n    x->right = base_node;\n    if (rightmost() == x)\n      rightmost() = base_node;\n  }\n  rb_tree_insert_rebalance(base_node, root());\n  ++node_count_;\n  return iterator(node);\n}\n\n// 插入元素，键值允许重复，使用 hint\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator \nrb_tree<T, Compare>::\ninsert_multi_use_hint(iterator hint, key_type key, node_ptr node)\n{\n  // 在 hint 附近寻找可插入的位置\n  auto np = hint.node;\n  auto before = hint;\n  --before;\n  auto bnp = before.node;\n  if (!key_comp_(key, value_traits::get_key(*before)) &&\n      !key_comp_(value_traits::get_key(*hint), key))\n  { // before <= node <= hint\n    if (bnp->right == nullptr)\n    {\n      return insert_node_at(bnp, node, false);\n    }\n    else if (np->left == nullptr)\n    {\n      return insert_node_at(np, node, true);\n    }\n  }\n  auto pos = get_insert_multi_pos(key);\n  return insert_node_at(pos.first, node, pos.second);\n}\n\n// 插入元素，键值不允许重复，使用 hint\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::iterator \nrb_tree<T, Compare>::\ninsert_unique_use_hint(iterator hint, key_type key, node_ptr node)\n{\n  // 在 hint 附近寻找可插入的位置\n  auto np = hint.node;\n  auto before = hint;\n  --before;\n  auto bnp = before.node;\n  if (key_comp_(value_traits::get_key(*before), key) &&\n      key_comp_(key, value_traits::get_key(*hint)))\n  { // before < node < hint\n    if (bnp->right == nullptr)\n    {\n      return insert_node_at(bnp, node, false);\n    }\n    else if (np->left == nullptr)\n    {\n      return insert_node_at(np, node, true);\n    }\n  }\n  auto pos = get_insert_unique_pos(key);\n  if (!pos.second)\n  {\n    destroy_node(node);\n    return pos.first.first;\n  }\n  return insert_node_at(pos.first.first, node, pos.first.second);\n}\n\n// copy_from 函数\n// 递归复制一颗树，节点从 x 开始，p 为 x 的父节点\ntemplate <class T, class Compare>\ntypename rb_tree<T, Compare>::base_ptr\nrb_tree<T, Compare>::copy_from(base_ptr x, base_ptr p)\n{\n  auto top = clone_node(x);\n  top->parent = p;\n  try\n  {\n    if (x->right)\n      top->right = copy_from(x->right, top);\n    p = top;\n    x = x->left;\n    while (x != nullptr)\n    {\n      auto y = clone_node(x);\n      p->left = y;\n      y->parent = p;\n      if (x->right)\n        y->right = copy_from(x->right, y);\n      p = y;\n      x = x->left;\n    }\n  }\n  catch (...)\n  {\n    erase_since(top);\n    throw;\n  }\n  return top;\n}\n\n// erase_since 函数\n// 从 x 节点开始删除该节点及其子树\ntemplate <class T, class Compare>\nvoid rb_tree<T, Compare>::\nerase_since(base_ptr x)\n{\n  while (x != nullptr)\n  {\n    erase_since(x->right);\n    auto y = x->left;\n    destroy_node(x->get_node_ptr());\n    x = y;\n  }\n}\n\n// 重载比较操作符\ntemplate <class T, class Compare>\nbool operator==(const rb_tree<T, Compare>& lhs, const rb_tree<T, Compare>& rhs)\n{\n  return lhs.size() == rhs.size() && mystl::equal(lhs.begin(), lhs.end(), rhs.begin());\n}\n\ntemplate <class T, class Compare>\nbool operator<(const rb_tree<T, Compare>& lhs, const rb_tree<T, Compare>& rhs)\n{\n  return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());\n}\n\ntemplate <class T, class Compare>\nbool operator!=(const rb_tree<T, Compare>& lhs, const rb_tree<T, Compare>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class T, class Compare>\nbool operator>(const rb_tree<T, Compare>& lhs, const rb_tree<T, Compare>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class T, class Compare>\nbool operator<=(const rb_tree<T, Compare>& lhs, const rb_tree<T, Compare>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class T, class Compare>\nbool operator>=(const rb_tree<T, Compare>& lhs, const rb_tree<T, Compare>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class T, class Compare>\nvoid swap(rb_tree<T, Compare>& lhs, rb_tree<T, Compare>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_RB_TREE_H_\n\n"
  },
  {
    "path": "MyTinySTL/set.h",
    "content": "﻿#ifndef MYTINYSTL_SET_H_\n#define MYTINYSTL_SET_H_\n\n// 这个头文件包含两个模板类 set 和 multiset\n// set      : 集合，键值即实值，集合内元素会自动排序，键值不允许重复\n// multiset : 集合，键值即实值，集合内元素会自动排序，键值允许重复\n\n// notes:\n//\n// 异常保证：\n// mystl::set<Key> / mystl::multiset<Key> 满足基本异常保证，对以下等函数做强异常安全保证：\n//   * emplace\n//   * emplace_hint\n//   * insert\n\n#include \"rb_tree.h\"\n\nnamespace mystl\n{\n\n// 模板类 set，键值不允许重复\n// 参数一代表键值类型，参数二代表键值比较方式，缺省使用 mystl::less \ntemplate <class Key, class Compare = mystl::less<Key>>\nclass set\n{\npublic:\n  typedef Key        key_type;\n  typedef Key        value_type;\n  typedef Compare    key_compare;\n  typedef Compare    value_compare;\n\nprivate:\n  // 以 mystl::rb_tree 作为底层机制\n  typedef mystl::rb_tree<value_type, key_compare>  base_type;\n  base_type tree_;\n\npublic:\n  // 使用 rb_tree 定义的型别\n  typedef typename base_type::node_type              node_type;\n  typedef typename base_type::const_pointer          pointer;\n  typedef typename base_type::const_pointer          const_pointer;\n  typedef typename base_type::const_reference        reference;\n  typedef typename base_type::const_reference        const_reference;\n  typedef typename base_type::const_iterator         iterator;\n  typedef typename base_type::const_iterator         const_iterator;\n  typedef typename base_type::const_reverse_iterator reverse_iterator;\n  typedef typename base_type::const_reverse_iterator const_reverse_iterator;\n  typedef typename base_type::size_type              size_type;\n  typedef typename base_type::difference_type        difference_type;\n  typedef typename base_type::allocator_type         allocator_type;\n\npublic:\n  // 构造、复制、移动函数\n  set() = default;\n\n  template <class InputIterator>\n  set(InputIterator first, InputIterator last) \n    :tree_() \n  { tree_.insert_unique(first, last); }\n  set(std::initializer_list<value_type> ilist)\n    :tree_()\n  { tree_.insert_unique(ilist.begin(), ilist.end()); }\n\n  set(const set& rhs) \n    :tree_(rhs.tree_)\n  {\n  }\n  set(set&& rhs) noexcept\n    :tree_(mystl::move(rhs.tree_))\n  {\n  }\n\n  set& operator=(const set& rhs)\n  {\n    tree_ = rhs.tree_;\n    return *this;\n  }\n  set& operator=(set&& rhs)\n  { \n    tree_ = mystl::move(rhs.tree_); \n    return *this; \n  }\n  set& operator=(std::initializer_list<value_type> ilist)\n  {\n    tree_.clear();\n    tree_.insert_unique(ilist.begin(), ilist.end());\n    return *this;\n  }\n\n  // 相关接口\n\n  key_compare      key_comp()      const { return tree_.key_comp(); }\n  value_compare    value_comp()    const { return tree_.key_comp(); }\n  allocator_type   get_allocator() const { return tree_.get_allocator(); }\n\n  // 迭代器相关\n\n  iterator               begin()         noexcept\n  { return tree_.begin(); }\n  const_iterator         begin()   const noexcept\n  { return tree_.begin(); }\n  iterator               end()           noexcept\n  { return tree_.end(); }\n  const_iterator         end()     const noexcept\n  { return tree_.end(); }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return const_reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return const_reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关\n  bool                   empty()    const noexcept { return tree_.empty(); }\n  size_type              size()     const noexcept { return tree_.size(); }\n  size_type              max_size() const noexcept { return tree_.max_size(); }\n\n  // 插入删除操作\n\n  template <class ...Args>\n  pair<iterator, bool> emplace(Args&& ...args)\n  {\n    return tree_.emplace_unique(mystl::forward<Args>(args)...);\n  }\n\n  template <class ...Args>\n  iterator emplace_hint(iterator hint, Args&& ...args)\n  {\n    return tree_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...);\n  }\n\n  pair<iterator, bool> insert(const value_type& value)\n  {\n    return tree_.insert_unique(value);\n  }\n  pair<iterator, bool> insert(value_type&& value)\n  {\n    return tree_.insert_unique(mystl::move(value));\n  }\n\n  iterator insert(iterator hint, const value_type& value)\n  {\n    return tree_.insert_unique(hint, value);\n  }\n  iterator insert(iterator hint, value_type&& value)\n  {\n    return tree_.insert_unique(hint, mystl::move(value));\n  }\n\n  template <class InputIterator>\n  void insert(InputIterator first, InputIterator last)\n  {\n    tree_.insert_unique(first, last);\n  }\n\n  void      erase(iterator position)             { tree_.erase(position); }\n  size_type erase(const key_type& key)           { return tree_.erase_unique(key); }\n  void      erase(iterator first, iterator last) { tree_.erase(first, last); }\n\n  void      clear() { tree_.clear(); }\n\n  // set 相关操作\n\n  iterator       find(const key_type& key)              { return tree_.find(key); }\n  const_iterator find(const key_type& key)        const { return tree_.find(key); }\n\n  size_type      count(const key_type& key)       const { return tree_.count_unique(key); }\n\n  iterator       lower_bound(const key_type& key)       { return tree_.lower_bound(key); }\n  const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }\n\n  iterator       upper_bound(const key_type& key)       { return tree_.upper_bound(key); }\n  const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }\n\n  pair<iterator, iterator>\n    equal_range(const key_type& key)\n  { return tree_.equal_range_unique(key); }\n\n  pair<const_iterator, const_iterator>\n    equal_range(const key_type& key) const\n  { return tree_.equal_range_unique(key); }\n\n  void swap(set& rhs) noexcept\n  { tree_.swap(rhs.tree_); }\n\npublic:\n  friend bool operator==(const set& lhs, const set& rhs) { return lhs.tree_ == rhs.tree_; }\n  friend bool operator< (const set& lhs, const set& rhs) { return lhs.tree_ <  rhs.tree_; }\n};\n\n// 重载比较操作符\ntemplate <class Key, class Compare>\nbool operator==(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class Compare>\nbool operator<(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)\n{\n  return lhs < rhs;\n}\n\ntemplate <class Key, class Compare>\nbool operator!=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class Key, class Compare>\nbool operator>(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class Key, class Compare>\nbool operator<=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class Key, class Compare>\nbool operator>=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class Compare>\nvoid swap(set<Key, Compare>& lhs, set<Key, Compare>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n/*****************************************************************************************/\n\n// 模板类 multiset，键值允许重复\n// 参数一代表键值类型，参数二代表键值比较方式，缺省使用 mystl::less \ntemplate <class Key, class Compare = mystl::less<Key>>\nclass multiset\n{\npublic:\n  typedef Key        key_type;\n  typedef Key        value_type;\n  typedef Compare    key_compare;\n  typedef Compare    value_compare;\n\nprivate:\n  // 以 mystl::rb_tree 作为底层机制\n  typedef mystl::rb_tree<value_type, key_compare>  base_type;\n  base_type tree_;  // 以 rb_tree 表现 multiset\n\npublic:\n  // 使用 rb_tree 定义的型别\n  typedef typename base_type::node_type              node_type;\n  typedef typename base_type::const_pointer          pointer;\n  typedef typename base_type::const_pointer          const_pointer;\n  typedef typename base_type::const_reference        reference;\n  typedef typename base_type::const_reference        const_reference;\n  typedef typename base_type::const_iterator         iterator;\n  typedef typename base_type::const_iterator         const_iterator;\n  typedef typename base_type::const_reverse_iterator reverse_iterator;\n  typedef typename base_type::const_reverse_iterator const_reverse_iterator;\n  typedef typename base_type::size_type              size_type;\n  typedef typename base_type::difference_type        difference_type;\n  typedef typename base_type::allocator_type         allocator_type;\n\npublic:\n  // 构造、复制、移动函数\n  multiset() = default;\n\n  template <class InputIterator>\n  multiset(InputIterator first, InputIterator last) \n    :tree_() \n  { tree_.insert_multi(first, last); }\n  multiset(std::initializer_list<value_type> ilist)\n    :tree_() \n  { tree_.insert_multi(ilist.begin(), ilist.end()); }\n\n  multiset(const multiset& rhs)\n    :tree_(rhs.tree_)\n  {\n  }\n  multiset(multiset&& rhs) noexcept\n    :tree_(mystl::move(rhs.tree_))\n  {\n  }\n\n  multiset& operator=(const multiset& rhs) \n  { \n    tree_ = rhs.tree_;\n    return *this; \n  }\n  multiset& operator=(multiset&& rhs)\n  {\n    tree_ = mystl::move(rhs.tree_);\n    return *this; \n  }\n  multiset& operator=(std::initializer_list<value_type> ilist)\n  {\n    tree_.clear();\n    tree_.insert_multi(ilist.begin(), ilist.end());\n    return *this;\n  }\n\n  // 相关接口\n\n  key_compare      key_comp()      const { return tree_.key_comp(); }\n  value_compare    value_comp()    const { return tree_.key_comp(); }\n  allocator_type   get_allocator() const { return tree_.get_allocator(); }\n\n  // 迭代器相关\n\n  iterator               begin()         noexcept\n  { return tree_.begin(); }\n  const_iterator         begin()   const noexcept\n  { return tree_.begin(); }\n  iterator               end()           noexcept\n  { return tree_.end(); }\n  const_iterator         end()     const noexcept\n  { return tree_.end(); }\n\n  reverse_iterator       rbegin()        noexcept\n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return const_reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept\n  { return const_reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept\n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关\n  bool                   empty()    const noexcept { return tree_.empty(); }\n  size_type              size()     const noexcept { return tree_.size(); }\n  size_type              max_size() const noexcept { return tree_.max_size(); }\n\n  // 插入删除操作\n\n  template <class ...Args>\n  iterator emplace(Args&& ...args)\n  {\n    return tree_.emplace_multi(mystl::forward<Args>(args)...);\n  }\n\n  template <class ...Args>\n  iterator emplace_hint(iterator hint, Args&& ...args)\n  {\n    return tree_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...);\n  }\n\n  iterator insert(const value_type& value)\n  {\n    return tree_.insert_multi(value);\n  }\n  iterator insert(value_type&& value)\n  {\n    return tree_.insert_multi(mystl::move(value));\n  }\n\n  iterator insert(iterator hint, const value_type& value)\n  {\n    return tree_.insert_multi(hint, value);\n  }\n  iterator insert(iterator hint, value_type&& value)\n  {\n    return tree_.insert_multi(hint, mystl::move(value));\n  }\n\n  template <class InputIterator>\n  void insert(InputIterator first, InputIterator last)\n  {\n    tree_.insert_multi(first, last);\n  }\n\n  void           erase(iterator position)             { tree_.erase(position); }\n  size_type      erase(const key_type& key)           { return tree_.erase_multi(key); }\n  void           erase(iterator first, iterator last) { tree_.erase(first, last); }\n\n  void           clear() { tree_.clear(); }\n\n  // multiset 相关操作\n\n  iterator       find(const key_type& key)              { return tree_.find(key); }\n  const_iterator find(const key_type& key)        const { return tree_.find(key); }\n\n  size_type      count(const key_type& key)       const { return tree_.count_multi(key); }\n\n  iterator       lower_bound(const key_type& key)       { return tree_.lower_bound(key); }\n  const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }\n\n  iterator       upper_bound(const key_type& key)       { return tree_.upper_bound(key); }\n  const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }\n\n  pair<iterator, iterator>\n    equal_range(const key_type& key)\n  { return tree_.equal_range_multi(key); }\n\n  pair<const_iterator, const_iterator>\n    equal_range(const key_type& key) const\n  { return tree_.equal_range_multi(key); }\n\n  void swap(multiset& rhs) noexcept\n  { tree_.swap(rhs.tree_); }\n\npublic:\n  friend bool operator==(const multiset& lhs, const multiset& rhs) { return lhs.tree_ == rhs.tree_; }\n  friend bool operator< (const multiset& lhs, const multiset& rhs) { return lhs.tree_ <  rhs.tree_; }\n};\n\n// 重载比较操作符\ntemplate <class Key, class Compare>\nbool operator==(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class Compare>\nbool operator<(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)\n{\n  return lhs < rhs;\n}\n\ntemplate <class Key, class Compare>\nbool operator!=(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class Key, class Compare>\nbool operator>(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class Key, class Compare>\nbool operator<=(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class Key, class Compare>\nbool operator>=(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class Compare>\nvoid swap(multiset<Key, Compare>& lhs, multiset<Key, Compare>& rhs) noexcept\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_SET_H_\n\n"
  },
  {
    "path": "MyTinySTL/set_algo.h",
    "content": "﻿#ifndef MYTINYSTL_SET_ALGO_H_\n#define MYTINYSTL_SET_ALGO_H_\n\n// 这个头文件包含 set 的四种算法: union, intersection, difference, symmetric_difference\n// 所有函数都要求序列有序\n\n#include \"algobase.h\"\n#include \"iterator.h\"\n\nnamespace mystl\n{\n\n/*****************************************************************************************/\n// set_union\n// 计算 S1∪S2 的结果并保存到 result 中，返回一个迭代器指向输出结果的尾部\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2, class OutputIter>\nOutputIter set_union(InputIter1 first1, InputIter1 last1,\n                     InputIter2 first2, InputIter2 last2, \n                     OutputIter result)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (*first1 < *first2)\n    {\n      *result = *first1;\n      ++first1;\n    }\n    else if (*first2 < *first1)\n    {\n      *result = *first2;\n      ++first2;\n    }\n    else\n    {\n      *result = *first1;\n      ++first1;\n      ++first2;\n    }\n    ++result;\n  }\n  // 将剩余元素拷贝到 result\n  return mystl::copy(first2, last2, mystl::copy(first1, last1, result));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class OutputIter, class Compared>\nOutputIter set_union(InputIter1 first1, InputIter1 last1,\n                     InputIter2 first2, InputIter2 last2, \n                     OutputIter result, Compared comp)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (comp(*first1, *first2))\n    {\n      *result = *first1;\n      ++first1;\n    }\n    else if (comp(*first2, *first1))\n    {\n      *result = *first2;\n      ++first2;\n    }\n    else\n    {\n      *result = *first1;\n      ++first1;\n      ++first2;\n    }\n    ++result;\n  }\n  // 将剩余元素拷贝到 result\n  return mystl::copy(first2, last2, mystl::copy(first1, last1, result));\n}\n\n/*****************************************************************************************/\n// set_intersection\n// 计算 S1∩S2 的结果并保存到 result 中，返回一个迭代器指向输出结果的尾部\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2, class OutputIter>\nOutputIter set_intersection(InputIter1 first1, InputIter1 last1,\n                            InputIter2 first2, InputIter2 last2, \n                            OutputIter result)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (*first1 < *first2)\n    {\n      ++first1;\n    }\n    else if (*first2 < *first1)\n    {\n      ++first2;\n    }\n    else\n    {\n      *result = *first1;\n      ++first1;\n      ++first2;\n      ++result;\n    }\n  }\n  return result;\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class OutputIter, class Compared>\nOutputIter set_intersection(InputIter1 first1, InputIter1 last1,\n                            InputIter2 first2, InputIter2 last2,\n                            OutputIter result, Compared comp)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (comp(*first1, *first2))\n    {\n      ++first1;\n    }\n    else if (comp(*first2, *first1))\n    {\n      ++first2;\n    }\n    else\n    {\n      *result = *first1;\n      ++first1;\n      ++first2;\n      ++result;\n    }\n  }\n  return result;\n}\n\n/*****************************************************************************************/\n// set_difference\n// 计算 S1-S2 的结果并保存到 result 中，返回一个迭代器指向输出结果的尾部\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2, class OutputIter>\nOutputIter set_difference(InputIter1 first1, InputIter1 last1,\n                          InputIter2 first2, InputIter2 last2,\n                          OutputIter result)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (*first1 < *first2)\n    {\n      *result = *first1;\n      ++first1;\n      ++result;\n    }\n    else if (*first2 < *first1)\n    {\n      ++first2;\n    }\n    else\n    {\n      ++first1;\n      ++first2;\n    }\n  }\n  return mystl::copy(first1, last1, result);\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class OutputIter, class Compared>\nOutputIter set_difference(InputIter1 first1, InputIter1 last1,\n                          InputIter2 first2, InputIter2 last2, \n                          OutputIter result, Compared comp)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (comp(*first1, *first2))\n    {\n      *result = *first1;\n      ++first1;\n      ++result;\n    }\n    else if (comp(*first2, *first1))\n    {\n      ++first2;\n    }\n    else\n    {\n      ++first1;\n      ++first2;\n    }\n  }\n  return mystl::copy(first1, last1, result);\n}\n\n/*****************************************************************************************/\n// set_symmetric_difference\n// 计算 (S1-S2)∪(S2-S1) 的结果并保存到 result 中，返回一个迭代器指向输出结果的尾部\n/*****************************************************************************************/\ntemplate <class InputIter1, class InputIter2, class OutputIter>\nOutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,\n                                    InputIter2 first2, InputIter2 last2, \n                                    OutputIter result)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (*first1 < *first2)\n    {\n      *result = *first1;\n      ++first1;\n      ++result;\n    }\n    else if (*first2 < *first1)\n    {\n      *result = *first2;\n      ++first2;\n      ++result;\n    }\n    else\n    {\n      ++first1;\n      ++first2;\n    }\n  }\n  return mystl::copy(first2, last2, mystl::copy(first1, last1, result));\n}\n\n// 重载版本使用函数对象 comp 代替比较操作\ntemplate <class InputIter1, class InputIter2, class OutputIter, class Compared>\nOutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,\n                                    InputIter2 first2, InputIter2 last2,\n                                    OutputIter result, Compared comp)\n{\n  while (first1 != last1 && first2 != last2)\n  {\n    if (comp(*first1, *first2))\n    {\n      *result = *first1;\n      ++first1;\n      ++result;\n    }\n    else if (comp(*first2, *first1))\n    {\n      *result = *first2;\n      ++first2;\n      ++result;\n    }\n    else\n    {\n      ++first1;\n      ++first2;\n    }\n  }\n  return mystl::copy(first2, last2, mystl::copy(first1, last1, result));\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_SET_ALGO_H_\n\n"
  },
  {
    "path": "MyTinySTL/stack.h",
    "content": "﻿#ifndef MYTINYSTL_STACK_H_\n#define MYTINYSTL_STACK_H_\n\n// 这个头文件包含了一个模板类 stack\n// stack : 栈\n\n#include \"deque.h\"    \n\nnamespace mystl\n{\n\n// 模板类 stack\n// 参数一代表数据类型，参数二代表底层容器类型，缺省使用 mystl::deque 作为底层容器\ntemplate <class T, class Container = mystl::deque<T>>\nclass stack\n{\npublic:\n  typedef Container                           container_type;\n  // 使用底层容器的型别\n  typedef typename Container::value_type      value_type;\n  typedef typename Container::size_type       size_type;\n  typedef typename Container::reference       reference;\n  typedef typename Container::const_reference const_reference;\n\n  static_assert(std::is_same<T, value_type>::value,\n                \"the value_type of Container should be same with T\");\nprivate:\n  container_type c_;  // 用底层容器表现 stack\n\npublic:\n  // 构造、复制、移动函数\n  stack() = default;\n\n  explicit stack(size_type n) \n    :c_(n)\n  {\n  }\n  stack(size_type n, const value_type& value) \n    :c_(n, value)\n  {\n  }\n\n  template <class IIter>\n  stack(IIter first, IIter last)\n    : c_(first, last)\n  {\n  }\n\n  stack(std::initializer_list<T> ilist) \n    :c_(ilist.begin(), ilist.end())\n  {\n  }\n\n  stack(const Container& c)\n    :c_(c)\n  {\n  }\n  stack(Container&& c) noexcept(std::is_nothrow_move_constructible<Container>::value)\n    :c_(mystl::move(c)) \n  {\n  }\n\n  stack(const stack& rhs) \n    :c_(rhs.c_) \n  {\n  }\n  stack(stack&& rhs) noexcept(std::is_nothrow_move_constructible<Container>::value)\n    :c_(mystl::move(rhs.c_))\n  {\n  }\n\n  stack& operator=(const stack& rhs)\n  {\n    c_ = rhs.c_;\n    return *this;\n  }\n  stack& operator=(stack&& rhs) noexcept(std::is_nothrow_move_assignable<Container>::value)\n  { \n    c_ = mystl::move(rhs.c_); \n    return *this;\n  }\n\n  stack& operator=(std::initializer_list<T> ilist) \n  {\n    c_ = ilist; \n    return *this;\n  }\n\n  ~stack() = default;\n\n  // 访问元素相关操作\n  reference       top()       { return c_.back(); }\n  const_reference top() const { return c_.back(); }\n\n  // 容量相关操作\n  bool      empty() const noexcept { return c_.empty(); }\n  size_type size()  const noexcept { return c_.size(); }\n\n  // 修改容器相关操作\n\n  template <class... Args>\n  void emplace(Args&& ...args)\n  { c_.emplace_back(mystl::forward<Args>(args)...); }\n\n  void push(const value_type& value)\n  { c_.push_back(value); }\n  void push(value_type&& value)      \n  { c_.push_back(mystl::move(value)); }\n\n  void pop() \n  { c_.pop_back(); }\n\n  void clear() \n  {\n    while (!empty())\n      pop();\n  }\n\n  void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)))\n  { mystl::swap(c_, rhs.c_); }\n\npublic:\n  friend bool operator==(const stack& lhs, const stack& rhs) { return lhs.c_ == rhs.c_; }\n  friend bool operator< (const stack& lhs, const stack& rhs) { return lhs.c_ <  rhs.c_; }\n};\n\n// 重载比较操作符\ntemplate <class T, class Container>\nbool operator==(const stack<T, Container>& lhs, const stack<T, Container>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class T, class Container>\nbool operator<(const stack<T, Container>& lhs, const stack<T, Container>& rhs)\n{\n  return lhs < rhs;\n}\n\ntemplate <class T, class Container>\nbool operator!=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class T, class Container>\nbool operator>(const stack<T, Container>& lhs, const stack<T, Container>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class T, class Container>\nbool operator<=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class T, class Container>\nbool operator>=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class T, class Container>\nvoid swap(stack<T, Container>& lhs, stack<T, Container>& rhs) noexcept(noexcept(lhs.swap(rhs)))\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_STACK_H_\n\n"
  },
  {
    "path": "MyTinySTL/stream_iterator.h",
    "content": "#ifndef MYTINYSTL_STREAM_ITERATOR_H_\n#define MYTINYSTL_STREAM_ITERATOR_H_\n\n#include \"basic_string.h\"\n\nnamespace mystl\n{\n\ntemplate<typename T, typename CharT = char,\n        typename Traits = std::char_traits<CharT>, typename Dist = ptrdiff_t>\nclass istream_iterator\n: public iterator<input_iterator_tag, T, Dist, const T*, const T&>\n{\npublic:\n    using char_type = CharT;\n    using traits_type = Traits;\n    using istream_type = std::basic_istream<CharT, Traits>;  \n\n    istream_iterator() /* noexcept(std::is_nothrow_default_constructible<T>::value) */\n        : m_stream{nullptr}, m_value{} {}\n\n    istream_iterator(istream_type& is)\n        : m_stream{std::addressof(is)}\n    { read(); }\n\n    istream_iterator(const istream_iterator& other) /* noexcept(std::is_nothrow_copy_constructible<T>::value) */\n        = default;   // memberwise copy\n\n    istream_iterator& operator=(const istream_iterator&) = default;   // memberwise copy-asgn\n    \n    ~istream_iterator() = default;\n\n    const T& operator*() const noexcept {\n        MYSTL_DEBUG(m_stream != nullptr);\n        return m_value;\n    }\n\n    const T* operator->() const noexcept {\n        return std::addressof(*this);\n    }\n\n    istream_iterator& operator++() {\n        MYSTL_DEBUG(m_stream != nullptr);\n        read();\n        return *this;\n    }\n\n     istream_iterator operator++(int) {\n        auto tmp = *this;\n        ++*this;\n        return tmp;\n    }\n\nprivate:\n    istream_type* m_stream;\n    T m_value; \n\n    void read() {\n        if (m_stream && !(*m_stream >> m_value)) {  // m_stream 有效且读到 EOS\n            m_stream = nullptr;  \n        }\n    }  \n\n    friend bool operator==(const istream_iterator& lhs, const istream_iterator& rhs) {\n        return lhs.m_stream == rhs.m_stream;\n    }  \n\n    friend bool operator!=(const istream_iterator& lhs, const istream_iterator& rhs) {\n        return lhs.m_stream != rhs.m_stream;\n    }  \n};\n\n\n// TODO \n// template<typename T, typename CharT = char,\n//          typename Traits = char_traits<CharT> >\n// class ostream_iterator : public iterator<output_iterator_tag, void, void, void, void> {};\n}\n\n\n#endif"
  },
  {
    "path": "MyTinySTL/type_traits.h",
    "content": "﻿#ifndef MYTINYSTL_TYPE_TRAITS_H_\n#define MYTINYSTL_TYPE_TRAITS_H_\n\n// 这个头文件用于提取类型信息\n\n// use standard header for type_traits\n#include <type_traits>\n\nnamespace mystl\n{\n\n// helper struct\n\ntemplate <class T, T v>\nstruct m_integral_constant\n{\n  static constexpr T value = v;\n};\n\ntemplate <bool b>\nusing m_bool_constant = m_integral_constant<bool, b>;\n\ntypedef m_bool_constant<true>  m_true_type;\ntypedef m_bool_constant<false> m_false_type;\n\n/*****************************************************************************************/\n// type traits\n\n// is_pair\n\n// --- forward declaration begin\ntemplate <class T1, class T2>\nstruct pair;\n// --- forward declaration end\n\ntemplate <class T>\nstruct is_pair : mystl::m_false_type {};\n\ntemplate <class T1, class T2>\nstruct is_pair<mystl::pair<T1, T2>> : mystl::m_true_type {};\n\n} // namespace mystl\n\n#endif // !MYTINYSTL_TYPE_TRAITS_H_\n\n"
  },
  {
    "path": "MyTinySTL/uninitialized.h",
    "content": "﻿#ifndef MYTINYSTL_UNINITIALIZED_H_\n#define MYTINYSTL_UNINITIALIZED_H_\n\n// 这个头文件用于对未初始化空间构造元素\n\n#include \"algobase.h\"\n#include \"construct.h\"\n#include \"iterator.h\"\n#include \"type_traits.h\"\n#include \"util.h\"\n\nnamespace mystl\n{\n\n/*****************************************************************************************/\n// uninitialized_copy\n// 把 [first, last) 上的内容复制到以 result 为起始处的空间，返回复制结束的位置\n/*****************************************************************************************/\ntemplate <class InputIter, class ForwardIter>\nForwardIter \nunchecked_uninit_copy(InputIter first, InputIter last, ForwardIter result, std::true_type)\n{\n  return mystl::copy(first, last, result);\n}\n\ntemplate <class InputIter, class ForwardIter>\nForwardIter\nunchecked_uninit_copy(InputIter first, InputIter last, ForwardIter result, std::false_type)\n{\n  auto cur = result;\n  try\n  {\n    for (; first != last; ++first, ++cur)\n    {\n      mystl::construct(&*cur, *first);\n    }\n  }\n  catch (...)\n  {\n    for (; result != cur; --cur)\n      mystl::destroy(&*cur);\n  }\n  return cur;\n}\n\ntemplate <class InputIter, class ForwardIter>\nForwardIter uninitialized_copy(InputIter first, InputIter last, ForwardIter result)\n{\n  return mystl::unchecked_uninit_copy(first, last, result, \n                                     std::is_trivially_copy_assignable<\n                                     typename iterator_traits<ForwardIter>::\n                                     value_type>{});\n}\n\n/*****************************************************************************************/\n// uninitialized_copy_n\n// 把 [first, first + n) 上的内容复制到以 result 为起始处的空间，返回复制结束的位置\n/*****************************************************************************************/\ntemplate <class InputIter, class Size, class ForwardIter>\nForwardIter \nunchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, std::true_type)\n{\n  return mystl::copy_n(first, n, result).second;\n}\n\ntemplate <class InputIter, class Size, class ForwardIter>\nForwardIter\nunchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, std::false_type)\n{\n  auto cur = result;\n  try\n  {\n    for (; n > 0; --n, ++cur, ++first)\n    {\n      mystl::construct(&*cur, *first);\n    }\n  }\n  catch (...)\n  {\n    for (; result != cur; --cur)\n      mystl::destroy(&*cur);\n  }\n  return cur;\n}\n\ntemplate <class InputIter, class Size, class ForwardIter>\nForwardIter uninitialized_copy_n(InputIter first, Size n, ForwardIter result)\n{\n  return mystl::unchecked_uninit_copy_n(first, n, result,\n                                        std::is_trivially_copy_assignable<\n                                        typename iterator_traits<InputIter>::\n                                        value_type>{});\n}\n\n/*****************************************************************************************/\n// uninitialized_fill\n// 在 [first, last) 区间内填充元素值\n/*****************************************************************************************/\ntemplate <class ForwardIter, class T>\nvoid \nunchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, std::true_type)\n{\n  mystl::fill(first, last, value);\n}\n\ntemplate <class ForwardIter, class T>\nvoid \nunchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, std::false_type)\n{\n  auto cur = first;\n  try\n  {\n    for (; cur != last; ++cur)\n    {\n      mystl::construct(&*cur, value);\n    }\n  }\n  catch (...)\n  {\n    for (;first != cur; ++first)\n      mystl::destroy(&*first);\n  }\n}\n\ntemplate <class ForwardIter, class T>\nvoid  uninitialized_fill(ForwardIter first, ForwardIter last, const T& value)\n{\n  mystl::unchecked_uninit_fill(first, last, value, \n                               std::is_trivially_copy_assignable<\n                               typename iterator_traits<ForwardIter>::\n                               value_type>{});\n}\n\n/*****************************************************************************************/\n// uninitialized_fill_n\n// 从 first 位置开始，填充 n 个元素值，返回填充结束的位置\n/*****************************************************************************************/\ntemplate <class ForwardIter, class Size, class T>\nForwardIter \nunchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, std::true_type)\n{\n  return mystl::fill_n(first, n, value);\n}\n\ntemplate <class ForwardIter, class Size, class T>\nForwardIter \nunchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, std::false_type)\n{\n  auto cur = first;\n  try\n  {\n    for (; n > 0; --n, ++cur)\n    {\n      mystl::construct(&*cur, value);\n    }\n  }\n  catch (...)\n  {\n    for (; first != cur; ++first)\n      mystl::destroy(&*first);\n  }\n  return cur;\n}\n\ntemplate <class ForwardIter, class Size, class T>\nForwardIter uninitialized_fill_n(ForwardIter first, Size n, const T& value)\n{\n  return mystl::unchecked_uninit_fill_n(first, n, value, \n                                        std::is_trivially_copy_assignable<\n                                        typename iterator_traits<ForwardIter>::\n                                        value_type>{});\n}\n\n/*****************************************************************************************/\n// uninitialized_move\n// 把[first, last)上的内容移动到以 result 为起始处的空间，返回移动结束的位置\n/*****************************************************************************************/\ntemplate <class InputIter, class ForwardIter>\nForwardIter \nunchecked_uninit_move(InputIter first, InputIter last, ForwardIter result, std::true_type)\n{\n  return mystl::move(first, last, result);\n}\n\ntemplate <class InputIter, class ForwardIter>\nForwardIter \nunchecked_uninit_move(InputIter first, InputIter last, ForwardIter result, std::false_type)\n{\n  ForwardIter cur = result;\n  try\n  {\n    for (; first != last; ++first, ++cur)\n    {\n      mystl::construct(&*cur, mystl::move(*first));\n    }\n  }\n  catch (...)\n  {\n    mystl::destroy(result, cur);\n  }\n  return cur;\n}\n\ntemplate <class InputIter, class ForwardIter>\nForwardIter uninitialized_move(InputIter first, InputIter last, ForwardIter result)\n{\n  return mystl::unchecked_uninit_move(first, last, result,\n                                      std::is_trivially_move_assignable<\n                                      typename iterator_traits<InputIter>::\n                                      value_type>{});\n}\n\n/*****************************************************************************************/\n// uninitialized_move_n\n// 把[first, first + n)上的内容移动到以 result 为起始处的空间，返回移动结束的位置\n/*****************************************************************************************/\ntemplate <class InputIter, class Size, class ForwardIter>\nForwardIter \nunchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, std::true_type)\n{\n  return mystl::move(first, first + n, result);\n}\n\ntemplate <class InputIter, class Size, class ForwardIter>\nForwardIter\nunchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, std::false_type)\n{\n  auto cur = result;\n  try\n  {\n    for (; n > 0; --n, ++first, ++cur)\n    {\n      mystl::construct(&*cur, mystl::move(*first));\n    }\n  }\n  catch (...)\n  {\n    for (; result != cur; ++result)\n      mystl::destroy(&*result);\n    throw;\n  }\n  return cur;\n}\n\ntemplate <class InputIter, class Size, class ForwardIter>\nForwardIter uninitialized_move_n(InputIter first, Size n, ForwardIter result)\n{\n  return mystl::unchecked_uninit_move_n(first, n, result,\n                                        std::is_trivially_move_assignable<\n                                        typename iterator_traits<InputIter>::\n                                        value_type>{});\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_UNINITIALIZED_H_\n\n"
  },
  {
    "path": "MyTinySTL/unordered_map.h",
    "content": "﻿#ifndef MYTINYSTL_UNORDERED_MAP_H_\n#define MYTINYSTL_UNORDERED_MAP_H_\n\n// 这个头文件包含两个模板类 unordered_map 和 unordered_multimap\n// 功能与用法与 map 和 multimap 类似，不同的是使用 hashtable 作为底层实现机制，容器内的元素不会自动排序\n\n// notes:\n//\n// 异常保证：\n// mystl::unordered_map<Key, T> / mystl::unordered_multimap<Key, T> 满足基本异常保证，对以下等函数做强异常安全保证：\n//   * emplace\n//   * emplace_hint\n//   * insert\n\n#include \"hashtable.h\"\n\nnamespace mystl\n{\n\n// 模板类 unordered_map，键值不允许重复\n// 参数一代表键值类型，参数二代表实值类型，参数三代表哈希函数，缺省使用 mystl::hash\n// 参数四代表键值比较方式，缺省使用 mystl::equal_to\ntemplate <class Key, class T, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>\nclass unordered_map\n{\nprivate:\n  // 使用 hashtable 作为底层机制\n  typedef hashtable<mystl::pair<const Key, T>, Hash, KeyEqual> base_type;\n  base_type ht_;\n\npublic:\n  // 使用 hashtable 的型别  \n\n  typedef typename base_type::allocator_type       allocator_type;\n  typedef typename base_type::key_type             key_type;\n  typedef typename base_type::mapped_type          mapped_type;\n  typedef typename base_type::value_type           value_type;\n  typedef typename base_type::hasher               hasher;\n  typedef typename base_type::key_equal            key_equal;\n\n  typedef typename base_type::size_type            size_type;\n  typedef typename base_type::difference_type      difference_type;\n  typedef typename base_type::pointer              pointer;\n  typedef typename base_type::const_pointer        const_pointer;\n  typedef typename base_type::reference            reference;\n  typedef typename base_type::const_reference      const_reference;\n\n  typedef typename base_type::iterator             iterator;\n  typedef typename base_type::const_iterator       const_iterator;\n  typedef typename base_type::local_iterator       local_iterator;\n  typedef typename base_type::const_local_iterator const_local_iterator;\n\n  allocator_type get_allocator() const { return ht_.get_allocator(); }\n\npublic:\n  // 构造、复制、移动、析构函数\n\n  unordered_map()\n    :ht_(100, Hash(), KeyEqual())\n  {\n  }\n\n  explicit unordered_map(size_type bucket_count,\n                         const Hash& hash = Hash(),\n                         const KeyEqual& equal = KeyEqual())\n    :ht_(bucket_count, hash, equal)\n  {\n  }\n\n  template <class InputIterator>\n  unordered_map(InputIterator first, InputIterator last,\n                const size_type bucket_count = 100,\n                const Hash& hash = Hash(),\n                const KeyEqual& equal = KeyEqual())\n    : ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)\n  {\n    for (; first != last; ++first)\n      ht_.insert_unique_noresize(*first);\n  }\n\n  unordered_map(std::initializer_list<value_type> ilist,\n                const size_type bucket_count = 100,\n                const Hash& hash = Hash(),\n                const KeyEqual& equal = KeyEqual())\n    :ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)\n  {\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_unique_noresize(*first);\n  }\n\n  unordered_map(const unordered_map& rhs) \n    :ht_(rhs.ht_) \n  {\n  }\n  unordered_map(unordered_map&& rhs) noexcept\n    :ht_(mystl::move(rhs.ht_)) \n  {\n  }\n\n  unordered_map& operator=(const unordered_map& rhs) \n  { \n    ht_ = rhs.ht_;\n    return *this; \n  }\n  unordered_map& operator=(unordered_map&& rhs) \n  { \n    ht_ = mystl::move(rhs.ht_);\n    return *this;\n  }\n\n  unordered_map& operator=(std::initializer_list<value_type> ilist)\n  {\n    ht_.clear();\n    ht_.reserve(ilist.size());\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_unique_noresize(*first);\n    return *this;\n  }\n\n  ~unordered_map() = default;\n\n  // 迭代器相关\n\n  iterator       begin()        noexcept\n  { return ht_.begin(); }\n  const_iterator begin()  const noexcept\n  { return ht_.begin(); }\n  iterator       end()          noexcept\n  { return ht_.end(); }\n  const_iterator end()    const noexcept\n  { return ht_.end(); }\n\n  const_iterator cbegin() const noexcept\n  { return ht_.cbegin(); }\n  const_iterator cend()   const noexcept\n  { return ht_.cend(); }\n\n  // 容量相关\n\n  bool      empty()    const noexcept { return ht_.empty(); }\n  size_type size()     const noexcept { return ht_.size(); }\n  size_type max_size() const noexcept { return ht_.max_size(); }\n\n  // 修改容器操作\n\n  // empalce / empalce_hint\n\n  template <class ...Args>\n  pair<iterator, bool> emplace(Args&& ...args)\n  { return ht_.emplace_unique(mystl::forward<Args>(args)...); }\n\n  template <class ...Args>\n  iterator emplace_hint(const_iterator hint, Args&& ...args)\n  { return ht_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...); }\n\n  // insert\n\n  pair<iterator, bool> insert(const value_type& value)\n  { return ht_.insert_unique(value); }\n  pair<iterator, bool> insert(value_type&& value)\n  { return ht_.emplace_unique(mystl::move(value)); }\n\n  iterator insert(const_iterator hint, const value_type& value)\n  { return ht_.insert_unique_use_hint(hint, value); }\n  iterator insert(const_iterator hint, value_type&& value)\n  { return ht_.emplace_unique_use_hint(hint, mystl::move(value)); }\n\n  template <class InputIterator>\n  void insert(InputIterator first, InputIterator last)\n  { ht_.insert_unique(first, last); }\n\n  // erase / clear\n\n  void      erase(iterator it)\n  { ht_.erase(it); }\n  void      erase(iterator first, iterator last)\n  { ht_.erase(first, last); }\n\n  size_type erase(const key_type& key)\n  { return ht_.erase_unique(key); }\n\n  void      clear()\n  { ht_.clear(); }\n\n  void      swap(unordered_map& other) noexcept\n  { ht_.swap(other.ht_); }\n\n  // 查找相关\n\n  mapped_type& at(const key_type& key)\n  {\n    iterator it = ht_.find(key);\n    THROW_OUT_OF_RANGE_IF(it.node == nullptr, \"unordered_map<Key, T> no such element exists\");\n    return it->second;\n  }\n  const mapped_type& at(const key_type& key) const\n  {\n    iterator it = ht_.find(key);\n    THROW_OUT_OF_RANGE_IF(it.node == nullptr, \"unordered_map<Key, T> no such element exists\");\n    return it->second;\n  }\n\n  mapped_type& operator[](const key_type& key)\n  {\n    iterator it = ht_.find(key);\n    if (it.node == nullptr)\n      it = ht_.emplace_unique(key, T{}).first;\n    return it->second;\n  }\n  mapped_type& operator[](key_type&& key)\n  {\n    iterator it = ht_.find(key);\n    if (it.node == nullptr)\n      it = ht_.emplace_unique(mystl::move(key), T{}).first;\n    return it->second;\n  }\n\n  size_type      count(const key_type& key) const \n  { return ht_.count(key); }\n\n  iterator       find(const key_type& key)        \n  { return ht_.find(key); }\n  const_iterator find(const key_type& key)  const \n  { return ht_.find(key); }\n\n  pair<iterator, iterator> equal_range(const key_type& key)\n  { return ht_.equal_range_unique(key); }\n  pair<const_iterator, const_iterator> equal_range(const key_type& key) const\n  { return ht_.equal_range_unique(key); }\n\n  // bucket interface\n\n  local_iterator       begin(size_type n)        noexcept\n  { return ht_.begin(n); }\n  const_local_iterator begin(size_type n)  const noexcept\n  { return ht_.begin(n); }\n  const_local_iterator cbegin(size_type n) const noexcept\n  { return ht_.cbegin(n); }\n\n  local_iterator       end(size_type n)          noexcept\n  { return ht_.end(n); }\n  const_local_iterator end(size_type n)    const noexcept\n  { return ht_.end(n); }\n  const_local_iterator cend(size_type n)   const noexcept\n  { return ht_.cend(n); }\n\n  size_type bucket_count()                 const noexcept\n  { return ht_.bucket_count(); }\n  size_type max_bucket_count()             const noexcept\n  { return ht_.max_bucket_count(); }\n\n  size_type bucket_size(size_type n)       const noexcept\n  { return ht_.bucket_size(n); }\n  size_type bucket(const key_type& key)    const\n  { return ht_.bucket(key); }\n\n  // hash policy\n\n  float     load_factor()            const noexcept { return ht_.load_factor(); }\n\n  float     max_load_factor()        const noexcept { return ht_.max_load_factor(); }\n  void      max_load_factor(float ml)               { ht_.max_load_factor(ml); }\n\n  void      rehash(size_type count)                 { ht_.rehash(count); }\n  void      reserve(size_type count)                { ht_.reserve(count); }\n\n  hasher    hash_fcn()               const          { return ht_.hash_fcn(); }\n  key_equal key_eq()                 const          { return ht_.key_eq(); }\n\npublic:\n  friend bool operator==(const unordered_map& lhs, const unordered_map& rhs)\n  {\n    return lhs.ht_.equal_range_unique(rhs.ht_);\n  }\n  friend bool operator!=(const unordered_map& lhs, const unordered_map& rhs)\n  {\n    return !lhs.ht_.equal_range_unique(rhs.ht_);\n  }\n};\n\n// 重载比较操作符\ntemplate <class Key, class T, class Hash, class KeyEqual>\nbool operator==(const unordered_map<Key, T, Hash, KeyEqual>& lhs,\n                const unordered_map<Key, T, Hash, KeyEqual>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class T, class Hash, class KeyEqual>\nbool operator!=(const unordered_map<Key, T, Hash, KeyEqual>& lhs,\n                const unordered_map<Key, T, Hash, KeyEqual>& rhs)\n{\n  return lhs != rhs;\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class T, class Hash, class KeyEqual>\nvoid swap(unordered_map<Key, T, Hash, KeyEqual>& lhs,\n          unordered_map<Key, T, Hash, KeyEqual>& rhs)\n{\n  lhs.swap(rhs);\n}\n\n/*****************************************************************************************/\n\n// 模板类 unordered_multimap，键值允许重复\n// 参数一代表键值类型，参数二代表实值类型，参数三代表哈希函数，缺省使用 mystl::hash\n// 参数四代表键值比较方式，缺省使用 mystl::equal_to\ntemplate <class Key, class T, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>\nclass unordered_multimap\n{\nprivate:\n  // 使用 hashtable 作为底层机制\n  typedef hashtable<pair<const Key, T>, Hash, KeyEqual> base_type;\n  base_type ht_;\n\npublic:\n  // 使用 hashtable 的型别\n  typedef typename base_type::allocator_type       allocator_type;\n  typedef typename base_type::key_type             key_type;\n  typedef typename base_type::mapped_type          mapped_type;\n  typedef typename base_type::value_type           value_type;\n  typedef typename base_type::hasher               hasher;\n  typedef typename base_type::key_equal            key_equal;\n\n  typedef typename base_type::size_type            size_type;\n  typedef typename base_type::difference_type      difference_type;\n  typedef typename base_type::pointer              pointer;\n  typedef typename base_type::const_pointer        const_pointer;\n  typedef typename base_type::reference            reference;\n  typedef typename base_type::const_reference      const_reference;\n\n  typedef typename base_type::iterator             iterator;\n  typedef typename base_type::const_iterator       const_iterator;\n  typedef typename base_type::local_iterator       local_iterator;\n  typedef typename base_type::const_local_iterator const_local_iterator;\n\n  allocator_type get_allocator() const { return ht_.get_allocator(); }\n\npublic:\n  // 构造、复制、移动函数\n\n  unordered_multimap() \n    :ht_(100, Hash(), KeyEqual())\n  {\n  }\n\n  explicit unordered_multimap(size_type bucket_count,\n                              const Hash& hash = Hash(),\n                              const KeyEqual& equal = KeyEqual())\n    :ht_(bucket_count, hash, equal) \n  {\n  }\n\n  template <class InputIterator>\n  unordered_multimap(InputIterator first, InputIterator last,\n                     const size_type bucket_count = 100,\n                     const Hash& hash = Hash(),\n                     const KeyEqual& equal = KeyEqual())\n    :ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)\n  {\n    for (; first != last; ++first)\n      ht_.insert_multi_noresize(*first);\n  }\n\n  unordered_multimap(std::initializer_list<value_type> ilist,\n                     const size_type bucket_count = 100,\n                     const Hash& hash = Hash(),\n                     const KeyEqual& equal = KeyEqual())\n    :ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)\n  {\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_multi_noresize(*first);\n  }\n\n  unordered_multimap(const unordered_multimap& rhs) \n    :ht_(rhs.ht_) \n  {\n  }\n  unordered_multimap(unordered_multimap&& rhs) noexcept\n    :ht_(mystl::move(rhs.ht_))\n  {\n  }\n\n  unordered_multimap& operator=(const unordered_multimap& rhs)\n  { \n    ht_ = rhs.ht_; \n    return *this;\n  }\n  unordered_multimap& operator=(unordered_multimap&& rhs)\n  { \n    ht_ = mystl::move(rhs.ht_); \n    return *this;\n  }\n\n  unordered_multimap& operator=(std::initializer_list<value_type> ilist)\n  {\n    ht_.clear();\n    ht_.reserve(ilist.size());\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_multi_noresize(*first);\n    return *this;\n  }\n\n  ~unordered_multimap() = default;\n\n  // 迭代器相关\n\n  iterator       begin()        noexcept\n  { return ht_.begin(); }\n  const_iterator begin()  const noexcept\n  { return ht_.begin(); }\n  iterator       end()          noexcept\n  { return ht_.end(); }\n  const_iterator end()    const noexcept\n  { return ht_.end(); }\n\n  const_iterator cbegin() const noexcept\n  { return ht_.cbegin(); }\n  const_iterator cend()   const noexcept\n  { return ht_.cend(); }\n\n  // 容量相关\n\n  bool      empty()    const noexcept { return ht_.empty(); }\n  size_type size()     const noexcept { return ht_.size(); }\n  size_type max_size() const noexcept { return ht_.max_size(); }\n\n  // 修改容器相关\n\n  // emplace / emplace_hint\n\n  template <class ...Args>\n  iterator emplace(Args&& ...args)\n  { return ht_.emplace_multi(mystl::forward<Args>(args)...); }\n\n  template <class ...Args>\n  iterator emplace_hint(const_iterator hint, Args&& ...args)\n  { return ht_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...); }\n\n  // insert\n\n  iterator insert(const value_type& value) \n  { return ht_.insert_multi(value); }\n  iterator insert(value_type&& value)\n  { return ht_.emplace_multi(mystl::move(value)); }\n\n  iterator insert(const_iterator hint, const value_type& value)\n  { return ht_.insert_multi_use_hint(hint, value); }\n  iterator insert(const_iterator hint, value_type&& value)\n  { return ht_.emplace_multi_use_hint(hint, mystl::move(value)); }\n\n  template <class InputIterator>\n  void     insert(InputIterator first, InputIterator last) \n  { ht_.insert_multi(first, last); }\n  \n  // erase / clear\n\n  void      erase(iterator it)\n  { ht_.erase(it); }\n  void      erase(iterator first, iterator last)\n  { ht_.erase(first, last); }\n\n  size_type erase(const key_type& key) \n  { return ht_.erase_multi(key); }\n\n  void      clear()\n  { ht_.clear(); }\n\n  void      swap(unordered_multimap& other) noexcept \n  { ht_.swap(other.ht_); }\n\n  // 查找相关\n\n  size_type      count(const key_type& key) const \n  { return ht_.count(key); }\n\n  iterator       find(const key_type& key)        \n  { return ht_.find(key); }\n  const_iterator find(const key_type& key)  const \n  { return ht_.find(key); }\n\n  pair<iterator, iterator> equal_range(const key_type& key) \n  { return ht_.equal_range_multi(key); }\n  pair<const_iterator, const_iterator> equal_range(const key_type& key) const \n  { return ht_.equal_range_multi(key); }\n\n  // bucket interface\n\n  local_iterator       begin(size_type n)        noexcept\n  { return ht_.begin(n); }\n  const_local_iterator begin(size_type n)  const noexcept\n  { return ht_.begin(n); }\n  const_local_iterator cbegin(size_type n) const noexcept\n  { return ht_.cbegin(n); }\n\n  local_iterator       end(size_type n)          noexcept\n  { return ht_.end(n); }\n  const_local_iterator end(size_type n)    const noexcept\n  { return ht_.end(n); }\n  const_local_iterator cend(size_type n)   const noexcept\n  { return ht_.cend(n); }\n\n  size_type bucket_count()                 const noexcept\n  { return ht_.bucket_count(); }\n  size_type max_bucket_count()             const noexcept\n  { return ht_.max_bucket_count(); }\n\n  size_type bucket_size(size_type n)       const noexcept\n  { return ht_.bucket_size(n); }\n  size_type bucket(const key_type& key)    const\n  { return ht_.bucket(key); }\n\n  // hash policy\n\n  float     load_factor()            const noexcept { return ht_.load_factor(); }\n\n  float     max_load_factor()        const noexcept { return ht_.max_load_factor(); }\n  void      max_load_factor(float ml)               { ht_.max_load_factor(ml); }\n\n  void      rehash(size_type count)                 { ht_.rehash(count); }\n  void      reserve(size_type count)                { ht_.reserve(count); }\n\n  hasher    hash_fcn()               const          { return ht_.hash_fcn(); }\n  key_equal key_eq()                 const          { return ht_.key_eq(); }\n\npublic:\n  friend bool operator==(const unordered_multimap& lhs, const unordered_multimap& rhs)\n  {\n    return lhs.ht_.equal_range_multi(rhs.ht_);\n  }\n  friend bool operator!=(const unordered_multimap& lhs, const unordered_multimap& rhs)\n  {\n    return !lhs.ht_.equal_range_multi(rhs.ht_);\n  }\n};\n\n// 重载比较操作符\ntemplate <class Key, class T, class Hash, class KeyEqual>\nbool operator==(const unordered_multimap<Key, T, Hash, KeyEqual>& lhs,\n                const unordered_multimap<Key, T, Hash, KeyEqual>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class T, class Hash, class KeyEqual>\nbool operator!=(const unordered_multimap<Key, T, Hash, KeyEqual>& lhs,\n                const unordered_multimap<Key, T, Hash, KeyEqual>& rhs)\n{\n  return lhs != rhs;\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class T, class Hash, class KeyEqual>\nvoid swap(unordered_multimap<Key, T, Hash, KeyEqual>& lhs,\n          unordered_multimap<Key, T, Hash, KeyEqual>& rhs)\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_UNORDERED_MAP_H_\n\n"
  },
  {
    "path": "MyTinySTL/unordered_set.h",
    "content": "﻿#ifndef MYTINYSTL_UNORDERED_SET_H_\n#define MYTINYSTL_UNORDERED_SET_H_\n\n// 这个头文件包含两个模板类 unordered_set 和 unordered_multiset\n// 功能与用法与 set 和 multiset 类似，不同的是使用 hashtable 作为底层实现机制，容器中的元素不会自动排序\n\n// notes:\n//\n// 异常保证：\n// mystl::unordered_set<Key> / mystl::unordered_multiset<Key> 满足基本异常保证，对以下等函数做强异常安全保证：\n//   * emplace\n//   * emplace_hint\n//   * insert\n\n#include \"hashtable.h\"\n\nnamespace mystl\n{\n\n// 模板类 unordered_set，键值不允许重复\n// 参数一代表键值类型，参数二代表哈希函数，缺省使用 mystl::hash，\n// 参数三代表键值比较方式，缺省使用 mystl::equal_to\ntemplate <class Key, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>\nclass unordered_set\n{\nprivate:\n  // 使用 hashtable 作为底层机制\n  typedef hashtable<Key, Hash, KeyEqual> base_type;\n  base_type ht_;\n\npublic:\n  // 使用 hashtable 的型别\n  typedef typename base_type::allocator_type       allocator_type;\n  typedef typename base_type::key_type             key_type;\n  typedef typename base_type::value_type           value_type;\n  typedef typename base_type::hasher               hasher;\n  typedef typename base_type::key_equal            key_equal;\n\n  typedef typename base_type::size_type            size_type;\n  typedef typename base_type::difference_type      difference_type;\n  typedef typename base_type::pointer              pointer;\n  typedef typename base_type::const_pointer        const_pointer;\n  typedef typename base_type::reference            reference;\n  typedef typename base_type::const_reference      const_reference;\n\n  typedef typename base_type::const_iterator       iterator;\n  typedef typename base_type::const_iterator       const_iterator;\n  typedef typename base_type::const_local_iterator local_iterator;\n  typedef typename base_type::const_local_iterator const_local_iterator;\n\n  allocator_type get_allocator() const { return ht_.get_allocator(); }\n\npublic:\n  // 构造、复制、移动函数\n\n  unordered_set()\n    :ht_(100, Hash(), KeyEqual())\n  {\n  }\n\n  explicit unordered_set(size_type bucket_count,\n                         const Hash& hash = Hash(),\n                         const KeyEqual& equal = KeyEqual())\n    :ht_(bucket_count, hash, equal)\n  {\n  }\n\n  template <class InputIterator>\n  unordered_set(InputIterator first, InputIterator last,\n                const size_type bucket_count = 100,\n                const Hash& hash = Hash(),\n                const KeyEqual& equal = KeyEqual())\n    : ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)\n  {\n    for (; first != last; ++first)\n      ht_.insert_unique_noresize(*first);\n  }\n\n  unordered_set(std::initializer_list<value_type> ilist,\n                const size_type bucket_count = 100,\n                const Hash& hash = Hash(),\n                const KeyEqual& equal = KeyEqual())\n    :ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)\n  {\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_unique_noresize(*first);\n  }\n\n  unordered_set(const unordered_set& rhs)\n    :ht_(rhs.ht_)\n  {\n  }\n  unordered_set(unordered_set&& rhs) noexcept\n    : ht_(mystl::move(rhs.ht_))\n  {\n  }\n\n  unordered_set& operator=(const unordered_set& rhs)\n  {\n    ht_ = rhs.ht_;\n    return *this;\n  }\n  unordered_set& operator=(unordered_set&& rhs)\n  {\n    ht_ = mystl::move(rhs.ht_);\n    return *this;\n  }\n\n  unordered_set& operator=(std::initializer_list<value_type> ilist)\n  {\n    ht_.clear();\n    ht_.reserve(ilist.size());\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_unique_noresize(*first);\n    return *this;\n  }\n\n  ~unordered_set() = default;\n\n  // 迭代器相关\n\n  iterator       begin()        noexcept\n  { return ht_.begin(); }\n  const_iterator begin()  const noexcept\n  { return ht_.begin(); }\n  iterator       end()          noexcept\n  { return ht_.end(); }\n  const_iterator end()    const noexcept\n  { return ht_.end(); }\n\n  const_iterator cbegin() const noexcept\n  { return ht_.cbegin(); }\n  const_iterator cend()   const noexcept\n  { return ht_.cend(); }\n\n  // 容量相关\n\n  bool      empty()    const noexcept { return ht_.empty(); }\n  size_type size()     const noexcept { return ht_.size(); }\n  size_type max_size() const noexcept { return ht_.max_size(); }\n\n  // 修改容器操作\n\n  // empalce / empalce_hint\n\n  template <class ...Args>\n  pair<iterator, bool> emplace(Args&& ...args)\n  { return ht_.emplace_unique(mystl::forward<Args>(args)...); }\n\n  template <class ...Args>\n  iterator emplace_hint(const_iterator hint, Args&& ...args)\n  { return ht_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...); }\n\n  // insert\n\n  pair<iterator, bool> insert(const value_type& value)\n  { return ht_.insert_unique(value); }\n  pair<iterator, bool> insert(value_type&& value)\n  { return ht_.emplace_unique(mystl::move(value)); }\n\n  iterator insert(const_iterator hint, const value_type& value)\n  { return ht_.insert_unique_use_hint(hint, value); }\n  iterator insert(const_iterator hint, value_type&& value)\n  { return ht_.emplace_unique_use_hint(hint, mystl::move(value)); }\n\n  template <class InputIterator>\n  void insert(InputIterator first, InputIterator last)\n  { ht_.insert_unique(first, last); }\n\n  // erase / clear\n\n  void      erase(iterator it)\n  { ht_.erase(it); }\n  void      erase(iterator first, iterator last)\n  { ht_.erase(first, last); }\n\n  size_type erase(const key_type& key)\n  { return ht_.erase_unique(key); }\n\n  void      clear()\n  { ht_.clear(); }\n\n  void      swap(unordered_set& other) noexcept\n  { ht_.swap(other.ht_); }\n\n  // 查找相关\n\n  size_type      count(const key_type& key) const \n  { return ht_.count(key); }\n\n  iterator       find(const key_type& key) \n  { return ht_.find(key); }\n  const_iterator find(const key_type& key)  const \n  { return ht_.find(key); }\n\n  pair<iterator, iterator> equal_range(const key_type& key)\n  { return ht_.equal_range_unique(key); }\n  pair<const_iterator, const_iterator> equal_range(const key_type& key) const\n  { return ht_.equal_range_unique(key); }\n\n  // bucket interface\n\n  local_iterator       begin(size_type n)        noexcept\n  { return ht_.begin(n); }\n  const_local_iterator begin(size_type n)  const noexcept\n  { return ht_.begin(n); }\n  const_local_iterator cbegin(size_type n) const noexcept\n  { return ht_.cbegin(n); }\n\n  local_iterator       end(size_type n)          noexcept\n  { return ht_.end(n); }\n  const_local_iterator end(size_type n)    const noexcept\n  { return ht_.end(n); }\n  const_local_iterator cend(size_type n)   const noexcept\n  { return ht_.cend(n); }\n\n  size_type bucket_count()                 const noexcept\n  { return ht_.bucket_count(); }\n  size_type max_bucket_count()             const noexcept\n  { return ht_.max_bucket_count(); }\n\n  size_type bucket_size(size_type n)       const noexcept\n  { return ht_.bucket_size(n); }\n  size_type bucket(const key_type& key)    const\n  { return ht_.bucket(key); }\n\n  // hash policy\n\n  float     load_factor()            const noexcept { return ht_.load_factor(); }\n\n  float     max_load_factor()        const noexcept { return ht_.max_load_factor(); }\n  void      max_load_factor(float ml)               { ht_.max_load_factor(ml); }\n\n  void      rehash(size_type count)                 { ht_.rehash(count); }\n  void      reserve(size_type count)                { ht_.reserve(count); }\n\n  hasher    hash_fcn()               const          { return ht_.hash_fcn(); }\n  key_equal key_eq()                 const          { return ht_.key_eq(); }\n\n\npublic:\n  friend bool operator==(const unordered_set& lhs, const unordered_set& rhs)\n  {\n    return lhs.ht_.equal_range_unique(rhs.ht_);\n  }\n  friend bool operator!=(const unordered_set& lhs, const unordered_set& rhs)\n  {\n    return !lhs.ht_.equal_range_unique(rhs.ht_);\n  }\n};\n\n// 重载比较操作符\ntemplate <class Key, class Hash, class KeyEqual, class Alloc>\nbool operator==(const unordered_set<Key, Hash, KeyEqual>& lhs,\n                const unordered_set<Key, Hash, KeyEqual>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class Hash, class KeyEqual, class Alloc>\nbool operator!=(const unordered_set<Key, Hash, KeyEqual>& lhs,\n                const unordered_set<Key, Hash, KeyEqual>& rhs)\n{\n  return lhs != rhs;\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class Hash, class KeyEqual, class Alloc>\nvoid swap(unordered_set<Key, Hash, KeyEqual>& lhs,\n          unordered_set<Key, Hash, KeyEqual>& rhs)\n{\n  lhs.swap(rhs);\n}\n\n/*****************************************************************************************/\n\n// 模板类 unordered_multiset，键值允许重复\n// 参数一代表键值类型，参数二代表哈希函数，缺省使用 mystl::hash，\n// 参数三代表键值比较方式，缺省使用 mystl::equal_to\ntemplate <class Key, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>\nclass unordered_multiset\n{\nprivate:\n  // 使用 hashtable 作为底层机制\n  typedef hashtable<Key, Hash, KeyEqual> base_type;\n  base_type ht_;\n\npublic:\n  // 使用 hashtable 的型别\n  typedef typename base_type::allocator_type       allocator_type;\n  typedef typename base_type::key_type             key_type;\n  typedef typename base_type::value_type           value_type;\n  typedef typename base_type::hasher               hasher;\n  typedef typename base_type::key_equal            key_equal;\n\n  typedef typename base_type::size_type            size_type;\n  typedef typename base_type::difference_type      difference_type;\n  typedef typename base_type::pointer              pointer;\n  typedef typename base_type::const_pointer        const_pointer;\n  typedef typename base_type::reference            reference;\n  typedef typename base_type::const_reference      const_reference;\n\n  typedef typename base_type::const_iterator       iterator;\n  typedef typename base_type::const_iterator       const_iterator;\n  typedef typename base_type::const_local_iterator local_iterator;\n  typedef typename base_type::const_local_iterator const_local_iterator;\n\n  allocator_type get_allocator() const { return ht_.get_allocator(); }\n\npublic:\n  // 构造、复制、移动函数\n\n  unordered_multiset()\n    :ht_(100, Hash(), KeyEqual())\n  {\n  }\n\n  explicit unordered_multiset(size_type bucket_count,\n                              const Hash& hash = Hash(),\n                              const KeyEqual& equal = KeyEqual())\n    :ht_(bucket_count, hash, equal)\n  {\n  }\n\n  template <class InputIterator>\n  unordered_multiset(InputIterator first, InputIterator last,\n                     const size_type bucket_count = 100,\n                     const Hash& hash = Hash(),\n                     const KeyEqual& equal = KeyEqual())\n    : ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)\n  {\n    for (; first != last; ++first)\n      ht_.insert_multi_noresize(*first);\n  }\n\n  unordered_multiset(std::initializer_list<value_type> ilist,\n                     const size_type bucket_count = 100,\n                     const Hash& hash = Hash(),\n                     const KeyEqual& equal = KeyEqual())\n    :ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)\n  {\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_multi_noresize(*first);\n  }\n\n  unordered_multiset(const unordered_multiset& rhs)\n    :ht_(rhs.ht_)\n  {\n  }\n  unordered_multiset(unordered_multiset&& rhs) noexcept\n    : ht_(mystl::move(rhs.ht_))\n  {\n  }\n\n  unordered_multiset& operator=(const unordered_multiset& rhs)\n  {\n    ht_ = rhs.ht_;\n    return *this;\n  }\n  unordered_multiset& operator=(unordered_multiset&& rhs)\n  {\n    ht_ = mystl::move(rhs.ht_);\n    return *this;\n  }\n\n  unordered_multiset& operator=(std::initializer_list<value_type> ilist)\n  {\n    ht_.clear();\n    ht_.reserve(ilist.size());\n    for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)\n      ht_.insert_multi_noresize(*first);\n    return *this;\n  }\n\n  ~unordered_multiset() = default;\n\n\n  // 迭代器相关\n\n  iterator       begin()        noexcept\n  { return ht_.begin(); }\n  const_iterator begin()  const noexcept\n  { return ht_.begin(); }\n  iterator       end()          noexcept\n  { return ht_.end(); }\n  const_iterator end()    const noexcept\n  { return ht_.end(); }\n\n  const_iterator cbegin() const noexcept\n  { return ht_.cbegin(); }\n  const_iterator cend()   const noexcept\n  { return ht_.cend(); }\n\n  // 容量相关\n\n  bool      empty()    const noexcept { return ht_.empty(); }\n  size_type size()     const noexcept { return ht_.size(); }\n  size_type max_size() const noexcept { return ht_.max_size(); }\n\n  // 修改容器相关\n\n  // emplace / emplace_hint\n\n  template <class ...Args>\n  iterator emplace(Args&& ...args)\n  { return ht_.emplace_multi(mystl::forward<Args>(args)...); }\n\n  template <class ...Args>\n  iterator emplace_hint(const_iterator hint, Args&& ...args)\n  { return ht_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...); }\n\n  // insert\n\n  iterator insert(const value_type& value)\n  { return ht_.insert_multi(value); }\n  iterator insert(value_type&& value)\n  { return ht_.emplace_multi(mystl::move(value)); }\n\n  iterator insert(const_iterator hint, const value_type& value)\n  { return ht_.insert_multi_use_hint(hint, value); }\n  iterator insert(const_iterator hint, value_type&& value)\n  { return ht_.emplace_multi_use_hint(hint, mystl::move(value)); }\n\n  template <class InputIterator>\n  void     insert(InputIterator first, InputIterator last)\n  { ht_.insert_multi(first, last); }\n\n  // erase / clear\n\n  void      erase(iterator it)\n  { ht_.erase(it); }\n  void      erase(iterator first, iterator last)\n  { ht_.erase(first, last); }\n\n  size_type erase(const key_type& key)\n  { return ht_.erase_multi(key); }\n\n  void      clear()\n  { ht_.clear(); }\n\n  void      swap(unordered_multiset& other) noexcept \n  { ht_.swap(other.ht_); }\n\n  // 查找相关\n\n  size_type      count(const key_type& key) const \n  { return ht_.count(key); }\n\n  iterator       find(const key_type& key) \n  { return ht_.find(key); }\n  const_iterator find(const key_type& key)  const \n  { return ht_.find(key); }\n\n  pair<iterator, iterator> equal_range(const key_type& key)\n  { return ht_.equal_range_multi(key); }\n  pair<const_iterator, const_iterator> equal_range(const key_type& key) const\n  { return ht_.equal_range_multi(key); }\n\n  // bucket interface\n\n  local_iterator       begin(size_type n)        noexcept\n  { return ht_.begin(n); }\n  const_local_iterator begin(size_type n)  const noexcept\n  { return ht_.begin(n); }\n  const_local_iterator cbegin(size_type n) const noexcept\n  { return ht_.cbegin(n); }\n\n  local_iterator       end(size_type n)          noexcept\n  { return ht_.end(n); }\n  const_local_iterator end(size_type n)    const noexcept\n  { return ht_.end(n); }\n  const_local_iterator cend(size_type n)   const noexcept\n  { return ht_.cend(n); }\n\n  size_type bucket_count()                 const noexcept\n  { return ht_.bucket_count(); }\n  size_type max_bucket_count()             const noexcept\n  { return ht_.max_bucket_count(); }\n\n  size_type bucket_size(size_type n)       const noexcept\n  { return ht_.bucket_size(n); }\n  size_type bucket(const key_type& key)    const\n  { return ht_.bucket(key); }\n\n  // hash policy\n\n  float     load_factor()            const noexcept { return ht_.load_factor(); }\n\n  float     max_load_factor()        const noexcept { return ht_.max_load_factor(); }\n  void      max_load_factor(float ml)               { ht_.max_load_factor(ml); }\n\n  void      rehash(size_type count)                 { ht_.rehash(count); }\n  void      reserve(size_type count)                { ht_.reserve(count); }\n\n  hasher    hash_fcn()               const          { return ht_.hash_fcn(); }\n  key_equal key_eq()                 const          { return ht_.key_eq(); }\n\npublic:\n  friend bool operator==(const unordered_multiset& lhs, const unordered_multiset& rhs)\n  {\n    return lhs.ht_.equal_range_multi(rhs.ht_);\n  }\n  friend bool operator!=(const unordered_multiset& lhs, const unordered_multiset& rhs)\n  {\n    return !lhs.ht_.equal_range_multi(rhs.ht_);\n  }\n};\n\n// 重载比较操作符\ntemplate <class Key, class Hash, class KeyEqual, class Alloc>\nbool operator==(const unordered_multiset<Key, Hash, KeyEqual>& lhs,\n                const unordered_multiset<Key, Hash, KeyEqual>& rhs)\n{\n  return lhs == rhs;\n}\n\ntemplate <class Key, class Hash, class KeyEqual, class Alloc>\nbool operator!=(const unordered_multiset<Key, Hash, KeyEqual>& lhs,\n                const unordered_multiset<Key, Hash, KeyEqual>& rhs)\n{\n  return lhs != rhs;\n}\n\n// 重载 mystl 的 swap\ntemplate <class Key, class Hash, class KeyEqual, class Alloc>\nvoid swap(unordered_multiset<Key, Hash, KeyEqual>& lhs,\n          unordered_multiset<Key, Hash, KeyEqual>& rhs)\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_UNORDERED_SET_H_\n\n"
  },
  {
    "path": "MyTinySTL/util.h",
    "content": "﻿#ifndef MYTINYSTL_UTIL_H_\n#define MYTINYSTL_UTIL_H_\n\n// 这个文件包含一些通用工具，包括 move, forward, swap 等函数，以及 pair 等 \n\n#include <cstddef>\n\n#include \"type_traits.h\"\n\nnamespace mystl\n{\n\n// move\n\ntemplate <class T>\ntypename std::remove_reference<T>::type&& move(T&& arg) noexcept\n{\n  return static_cast<typename std::remove_reference<T>::type&&>(arg);\n}\n\n// forward\n\ntemplate <class T>\nT&& forward(typename std::remove_reference<T>::type& arg) noexcept\n{\n  return static_cast<T&&>(arg);\n}\n\ntemplate <class T>\nT&& forward(typename std::remove_reference<T>::type&& arg) noexcept\n{\n  static_assert(!std::is_lvalue_reference<T>::value, \"bad forward\");\n  return static_cast<T&&>(arg);\n}\n\n// swap\n\ntemplate <class Tp>\nvoid swap(Tp& lhs, Tp& rhs)\n{\n  auto tmp(mystl::move(lhs));\n  lhs = mystl::move(rhs);\n  rhs = mystl::move(tmp);\n}\n\ntemplate <class ForwardIter1, class ForwardIter2>\nForwardIter2 swap_range(ForwardIter1 first1, ForwardIter1 last1, ForwardIter2 first2)\n{\n  for (; first1 != last1; ++first1, (void) ++first2)\n    mystl::swap(*first1, *first2);\n  return first2;\n}\n\ntemplate <class Tp, size_t N>\nvoid swap(Tp(&a)[N], Tp(&b)[N])\n{\n  mystl::swap_range(a, a + N, b);\n}\n\n// --------------------------------------------------------------------------------------\n// pair\n\n// 结构体模板 : pair\n// 两个模板参数分别表示两个数据的类型\n// 用 first 和 second 来分别取出第一个数据和第二个数据\ntemplate <class Ty1, class Ty2>\nstruct pair\n{\n  typedef Ty1    first_type;\n  typedef Ty2    second_type;\n\n  first_type first;    // 保存第一个数据\n  second_type second;  // 保存第二个数据\n\n  // default constructiable\n  template <class Other1 = Ty1, class Other2 = Ty2,\n    typename = typename std::enable_if<\n    std::is_default_constructible<Other1>::value &&\n    std::is_default_constructible<Other2>::value, void>::type>\n    constexpr pair()\n    : first(), second()\n  {\n  }\n\n  // implicit constructiable for this type\n  template <class U1 = Ty1, class U2 = Ty2,\n    typename std::enable_if<\n    std::is_copy_constructible<U1>::value &&\n    std::is_copy_constructible<U2>::value &&\n    std::is_convertible<const U1&, Ty1>::value &&\n    std::is_convertible<const U2&, Ty2>::value, int>::type = 0>\n    constexpr pair(const Ty1& a, const Ty2& b)\n    : first(a), second(b)\n  {\n  }\n\n  // explicit constructible for this type\n  template <class U1 = Ty1, class U2 = Ty2,\n    typename std::enable_if<\n    std::is_copy_constructible<U1>::value &&\n    std::is_copy_constructible<U2>::value &&\n    (!std::is_convertible<const U1&, Ty1>::value ||\n     !std::is_convertible<const U2&, Ty2>::value), int>::type = 0>\n    explicit constexpr pair(const Ty1& a, const Ty2& b)\n    : first(a), second(b)\n  {\n  }\n\n  pair(const pair& rhs) = default;\n  pair(pair&& rhs) = default;\n\n  // implicit constructiable for other type\n  template <class Other1, class Other2,\n    typename std::enable_if<\n    std::is_constructible<Ty1, Other1>::value &&\n    std::is_constructible<Ty2, Other2>::value &&\n    std::is_convertible<Other1&&, Ty1>::value &&\n    std::is_convertible<Other2&&, Ty2>::value, int>::type = 0>\n    constexpr pair(Other1&& a, Other2&& b)\n    : first(mystl::forward<Other1>(a)),\n    second(mystl::forward<Other2>(b))\n  {\n  }\n\n  // explicit constructiable for other type\n  template <class Other1, class Other2,\n    typename std::enable_if<\n    std::is_constructible<Ty1, Other1>::value &&\n    std::is_constructible<Ty2, Other2>::value &&\n    (!std::is_convertible<Other1, Ty1>::value ||\n     !std::is_convertible<Other2, Ty2>::value), int>::type = 0>\n    explicit constexpr pair(Other1&& a, Other2&& b)\n    : first(mystl::forward<Other1>(a)),\n    second(mystl::forward<Other2>(b))\n  {\n  }\n\n  // implicit constructiable for other pair\n  template <class Other1, class Other2,\n    typename std::enable_if<\n    std::is_constructible<Ty1, const Other1&>::value &&\n    std::is_constructible<Ty2, const Other2&>::value &&\n    std::is_convertible<const Other1&, Ty1>::value &&\n    std::is_convertible<const Other2&, Ty2>::value, int>::type = 0>\n    constexpr pair(const pair<Other1, Other2>& other)\n    : first(other.first),\n    second(other.second)\n  {\n  }\n\n  // explicit constructiable for other pair\n  template <class Other1, class Other2,\n    typename std::enable_if<\n    std::is_constructible<Ty1, const Other1&>::value &&\n    std::is_constructible<Ty2, const Other2&>::value &&\n    (!std::is_convertible<const Other1&, Ty1>::value ||\n     !std::is_convertible<const Other2&, Ty2>::value), int>::type = 0>\n    explicit constexpr pair(const pair<Other1, Other2>& other)\n    : first(other.first),\n    second(other.second)\n  {\n  }\n\n  // implicit constructiable for other pair\n  template <class Other1, class Other2,\n    typename std::enable_if<\n    std::is_constructible<Ty1, Other1>::value &&\n    std::is_constructible<Ty2, Other2>::value &&\n    std::is_convertible<Other1, Ty1>::value &&\n    std::is_convertible<Other2, Ty2>::value, int>::type = 0>\n    constexpr pair(pair<Other1, Other2>&& other)\n    : first(mystl::forward<Other1>(other.first)),\n    second(mystl::forward<Other2>(other.second))\n  {\n  }\n\n  // explicit constructiable for other pair\n  template <class Other1, class Other2,\n    typename std::enable_if<\n    std::is_constructible<Ty1, Other1>::value &&\n    std::is_constructible<Ty2, Other2>::value &&\n    (!std::is_convertible<Other1, Ty1>::value ||\n     !std::is_convertible<Other2, Ty2>::value), int>::type = 0>\n    explicit constexpr pair(pair<Other1, Other2>&& other)\n    : first(mystl::forward<Other1>(other.first)),\n    second(mystl::forward<Other2>(other.second))\n  {\n  }\n\n  // copy assign for this pair\n  pair& operator=(const pair& rhs)\n  {\n    if (this != &rhs)\n    {\n      first = rhs.first;\n      second = rhs.second;\n    }\n    return *this;\n  }\n\n  // move assign for this pair\n  pair& operator=(pair&& rhs)\n  {\n    if (this != &rhs)\n    {\n      first = mystl::move(rhs.first);\n      second = mystl::move(rhs.second);\n    }\n    return *this;\n  }\n\n  // copy assign for other pair\n  template <class Other1, class Other2>\n  pair& operator=(const pair<Other1, Other2>& other)\n  {\n    first = other.first;\n    second = other.second;\n    return *this;\n  }\n\n  // move assign for other pair\n  template <class Other1, class Other2>\n  pair& operator=(pair<Other1, Other2>&& other)\n  {\n    first = mystl::forward<Other1>(other.first);\n    second = mystl::forward<Other2>(other.second);\n    return *this;\n  }\n\n  ~pair() = default;\n\n  void swap(pair& other)\n  {\n    if (this != &other)\n    {\n      mystl::swap(first, other.first);\n      mystl::swap(second, other.second);\n    }\n  }\n\n};\n\n// 重载比较操作符 \ntemplate <class Ty1, class Ty2>\nbool operator==(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)\n{\n  return lhs.first == rhs.first && lhs.second == rhs.second;\n}\n\ntemplate <class Ty1, class Ty2>\nbool operator<(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)\n{\n  return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);\n}\n\ntemplate <class Ty1, class Ty2>\nbool operator!=(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class Ty1, class Ty2>\nbool operator>(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class Ty1, class Ty2>\nbool operator<=(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class Ty1, class Ty2>\nbool operator>=(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class Ty1, class Ty2>\nvoid swap(pair<Ty1, Ty2>& lhs, pair<Ty1, Ty2>& rhs)\n{\n  lhs.swap(rhs);\n}\n\n// 全局函数，让两个数据成为一个 pair\ntemplate <class Ty1, class Ty2>\npair<Ty1, Ty2> make_pair(Ty1&& first, Ty2&& second)\n{\n  return pair<Ty1, Ty2>(mystl::forward<Ty1>(first), mystl::forward<Ty2>(second));\n}\n\n}\n\n#endif // !MYTINYSTL_UTIL_H_\n\n"
  },
  {
    "path": "MyTinySTL/vector.h",
    "content": "﻿#ifndef MYTINYSTL_VECTOR_H_\n#define MYTINYSTL_VECTOR_H_\n\n// 这个头文件包含一个模板类 vector\n// vector : 向量\n\n// notes:\n//\n// 异常保证：\n// mystl::vecotr<T> 满足基本异常保证，部分函数无异常保证，并对以下函数做强异常安全保证：\n//   * emplace\n//   * emplace_back\n//   * push_back\n// 当 std::is_nothrow_move_assignable<T>::value == true 时，以下函数也满足强异常保证：\n//   * reserve\n//   * resize\n//   * insert\n\n#include <initializer_list>\n\n#include \"iterator.h\"\n#include \"memory.h\"\n#include \"util.h\"\n#include \"exceptdef.h\"\n#include \"algo.h\"\n\nnamespace mystl\n{\n\n#ifdef max\n#pragma message(\"#undefing marco max\")\n#undef max\n#endif // max\n\n#ifdef min\n#pragma message(\"#undefing marco min\")\n#undef min\n#endif // min\n\n// 模板类: vector \n// 模板参数 T 代表类型\ntemplate <class T>\nclass vector\n{\n  static_assert(!std::is_same<bool, T>::value, \"vector<bool> is abandoned in mystl\");\npublic:\n  // vector 的嵌套型别定义\n  typedef mystl::allocator<T>                      allocator_type;\n  typedef mystl::allocator<T>                      data_allocator;\n\n  typedef typename allocator_type::value_type      value_type;\n  typedef typename allocator_type::pointer         pointer;\n  typedef typename allocator_type::const_pointer   const_pointer;\n  typedef typename allocator_type::reference       reference;\n  typedef typename allocator_type::const_reference const_reference;\n  typedef typename allocator_type::size_type       size_type;\n  typedef typename allocator_type::difference_type difference_type;\n\n  typedef value_type*                              iterator;\n  typedef const value_type*                        const_iterator;\n  typedef mystl::reverse_iterator<iterator>        reverse_iterator;\n  typedef mystl::reverse_iterator<const_iterator>  const_reverse_iterator;\n\n  allocator_type get_allocator() { return data_allocator(); }\n\nprivate:\n  iterator begin_;  // 表示目前使用空间的头部\n  iterator end_;    // 表示目前使用空间的尾部\n  iterator cap_;    // 表示目前储存空间的尾部\n\npublic:\n  // 构造、复制、移动、析构函数\n  vector() noexcept\n  { try_init(); }\n\n  explicit vector(size_type n)\n  { fill_init(n, value_type()); }\n\n  vector(size_type n, const value_type& value)\n  { fill_init(n, value); }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  vector(Iter first, Iter last)\n  {\n    MYSTL_DEBUG(!(last < first));\n    range_init(first, last);\n  }\n\n  vector(const vector& rhs)\n  {\n    range_init(rhs.begin_, rhs.end_);\n  }\n\n  vector(vector&& rhs) noexcept\n    :begin_(rhs.begin_),\n    end_(rhs.end_),\n    cap_(rhs.cap_)\n  {\n    rhs.begin_ = nullptr;\n    rhs.end_ = nullptr;\n    rhs.cap_ = nullptr;\n  }\n\n  vector(std::initializer_list<value_type> ilist)\n  {\n    range_init(ilist.begin(), ilist.end());\n  }\n\n  vector& operator=(const vector& rhs);\n  vector& operator=(vector&& rhs) noexcept;\n\n  vector& operator=(std::initializer_list<value_type> ilist)\n  {\n    vector tmp(ilist.begin(), ilist.end());\n    swap(tmp);\n    return *this;\n  }\n\n  ~vector()\n  { \n    destroy_and_recover(begin_, end_, cap_ - begin_);\n    begin_ = end_ = cap_ = nullptr;\n  }\n\npublic:\n\n  // 迭代器相关操作\n  iterator               begin()         noexcept \n  { return begin_; }\n  const_iterator         begin()   const noexcept\n  { return begin_; }\n  iterator               end()           noexcept\n  { return end_; }\n  const_iterator         end()     const noexcept \n  { return end_; }\n\n  reverse_iterator       rbegin()        noexcept \n  { return reverse_iterator(end()); }\n  const_reverse_iterator rbegin()  const noexcept\n  { return const_reverse_iterator(end()); }\n  reverse_iterator       rend()          noexcept\n  { return reverse_iterator(begin()); }\n  const_reverse_iterator rend()    const noexcept \n  { return const_reverse_iterator(begin()); }\n\n  const_iterator         cbegin()  const noexcept \n  { return begin(); }\n  const_iterator         cend()    const noexcept\n  { return end(); }\n  const_reverse_iterator crbegin() const noexcept\n  { return rbegin(); }\n  const_reverse_iterator crend()   const noexcept\n  { return rend(); }\n\n  // 容量相关操作\n  bool      empty()    const noexcept\n  { return begin_ == end_; }\n  size_type size()     const noexcept\n  { return static_cast<size_type>(end_ - begin_); }\n  size_type max_size() const noexcept\n  { return static_cast<size_type>(-1) / sizeof(T); }\n  size_type capacity() const noexcept\n  { return static_cast<size_type>(cap_ - begin_); }\n  void      reserve(size_type n);\n  void      shrink_to_fit();\n\n  // 访问元素相关操作\n  reference operator[](size_type n)\n  {\n    MYSTL_DEBUG(n < size());\n    return *(begin_ + n);\n  }\n  const_reference operator[](size_type n) const\n  {\n    MYSTL_DEBUG(n < size());\n    return *(begin_ + n);\n  }\n  reference at(size_type n)\n  {\n    THROW_OUT_OF_RANGE_IF(!(n < size()), \"vector<T>::at() subscript out of range\");\n    return (*this)[n];\n  }\n  const_reference at(size_type n) const\n  {\n    THROW_OUT_OF_RANGE_IF(!(n < size()), \"vector<T>::at() subscript out of range\");\n    return (*this)[n];\n  }\n\n  reference front()\n  {\n    MYSTL_DEBUG(!empty());\n    return *begin_;\n  }\n  const_reference front() const\n  {\n    MYSTL_DEBUG(!empty());\n    return *begin_;\n  }\n  reference back()\n  {\n    MYSTL_DEBUG(!empty());\n    return *(end_ - 1);\n  }\n  const_reference back() const\n  {\n    MYSTL_DEBUG(!empty());\n    return *(end_ - 1);\n  }\n\n  pointer       data()       noexcept { return begin_; }\n  const_pointer data() const noexcept { return begin_; }\n\n  // 修改容器相关操作\n\n  // assign\n\n  void assign(size_type n, const value_type& value)\n  { fill_assign(n, value); }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  void assign(Iter first, Iter last)\n  {\n    MYSTL_DEBUG(!(last < first));\n    copy_assign(first, last, iterator_category(first));\n  }\n\n  void assign(std::initializer_list<value_type> il)\n  { copy_assign(il.begin(), il.end(), mystl::forward_iterator_tag{}); }\n\n  // emplace / emplace_back\n\n  template <class... Args>\n  iterator emplace(const_iterator pos, Args&& ...args);\n\n  template <class... Args>\n  void emplace_back(Args&& ...args);\n\n  // push_back / pop_back\n\n  void push_back(const value_type& value);\n  void push_back(value_type&& value)\n  { emplace_back(mystl::move(value)); }\n\n  void pop_back();\n\n  // insert\n\n  iterator insert(const_iterator pos, const value_type& value);\n  iterator insert(const_iterator pos, value_type&& value)\n  { return emplace(pos, mystl::move(value)); }\n\n  iterator insert(const_iterator pos, size_type n, const value_type& value)\n  {\n    MYSTL_DEBUG(pos >= begin() && pos <= end());\n    return fill_insert(const_cast<iterator>(pos), n, value);\n  }\n\n  template <class Iter, typename std::enable_if<\n    mystl::is_input_iterator<Iter>::value, int>::type = 0>\n  void     insert(const_iterator pos, Iter first, Iter last)\n  {\n    MYSTL_DEBUG(pos >= begin() && pos <= end() && !(last < first));\n    copy_insert(const_cast<iterator>(pos), first, last);\n  }\n\n  // erase / clear\n  iterator erase(const_iterator pos);\n  iterator erase(const_iterator first, const_iterator last);\n  void     clear() { erase(begin(), end()); }\n\n  // resize / reverse\n  void     resize(size_type new_size) { return resize(new_size, value_type()); }\n  void     resize(size_type new_size, const value_type& value);\n\n  void     reverse() { mystl::reverse(begin(), end()); }\n\n  // swap\n  void     swap(vector& rhs) noexcept;\n\nprivate:\n  // helper functions\n\n  // initialize / destroy\n  void      try_init() noexcept;\n\n  void      init_space(size_type size, size_type cap);\n\n  void      fill_init(size_type n, const value_type& value);\n  template <class Iter>\n  void      range_init(Iter first, Iter last);\n\n  void      destroy_and_recover(iterator first, iterator last, size_type n);\n\n  // calculate the growth size\n  size_type get_new_cap(size_type add_size);\n\n  // assign\n\n  void      fill_assign(size_type n, const value_type& value);\n\n  template <class IIter>\n  void      copy_assign(IIter first, IIter last, input_iterator_tag);\n\n  template <class FIter>\n  void      copy_assign(FIter first, FIter last, forward_iterator_tag);\n\n  // reallocate\n\n  template <class... Args>\n  void      reallocate_emplace(iterator pos, Args&& ...args);\n  void      reallocate_insert(iterator pos, const value_type& value);\n\n  // insert\n\n  iterator  fill_insert(iterator pos, size_type n, const value_type& value);\n  template <class IIter>\n  void      copy_insert(iterator pos, IIter first, IIter last);\n\n  // shrink_to_fit\n\n  void      reinsert(size_type size);\n};\n\n/*****************************************************************************************/\n\n// 复制赋值操作符\ntemplate <class T>\nvector<T>& vector<T>::operator=(const vector& rhs)\n{\n  if (this != &rhs)\n  {\n    const auto len = rhs.size();\n    if (len > capacity())\n    { \n      vector tmp(rhs.begin(), rhs.end());\n      swap(tmp);\n    }\n    else if (size() >= len)\n    {\n      auto i = mystl::copy(rhs.begin(), rhs.end(), begin());\n      data_allocator::destroy(i, end_);\n      end_ = begin_ + len;\n    }\n    else\n    { \n      mystl::copy(rhs.begin(), rhs.begin() + size(), begin_);\n      mystl::uninitialized_copy(rhs.begin() + size(), rhs.end(), end_);\n      cap_ = end_ = begin_ + len;\n    }\n  }\n  return *this;\n}\n\n// 移动赋值操作符\ntemplate <class T>\nvector<T>& vector<T>::operator=(vector&& rhs) noexcept\n{\n  destroy_and_recover(begin_, end_, cap_ - begin_);\n  begin_ = rhs.begin_;\n  end_ = rhs.end_;\n  cap_ = rhs.cap_;\n  rhs.begin_ = nullptr;\n  rhs.end_ = nullptr;\n  rhs.cap_ = nullptr;\n  return *this;\n}\n\n// 预留空间大小，当原容量小于要求大小时，才会重新分配\ntemplate <class T>\nvoid vector<T>::reserve(size_type n)\n{\n  if (capacity() < n)\n  {\n    THROW_LENGTH_ERROR_IF(n > max_size(),\n                          \"n can not larger than max_size() in vector<T>::reserve(n)\");\n    const auto old_size = size();\n    auto tmp = data_allocator::allocate(n);\n    mystl::uninitialized_move(begin_, end_, tmp);\n    data_allocator::deallocate(begin_, cap_ - begin_);\n    begin_ = tmp;\n    end_ = tmp + old_size;\n    cap_ = begin_ + n;\n  }\n}\n\n// 放弃多余的容量\ntemplate <class T>\nvoid vector<T>::shrink_to_fit()\n{\n  if (end_ < cap_)\n  {\n    reinsert(size());\n  }\n}\n\n// 在 pos 位置就地构造元素，避免额外的复制或移动开销\ntemplate <class T>\ntemplate <class ...Args>\ntypename vector<T>::iterator\nvector<T>::emplace(const_iterator pos, Args&& ...args)\n{\n  MYSTL_DEBUG(pos >= begin() && pos <= end());\n  iterator xpos = const_cast<iterator>(pos);\n  const size_type n = xpos - begin_;\n  if (end_ != cap_ && xpos == end_)\n  {\n    data_allocator::construct(mystl::address_of(*end_), mystl::forward<Args>(args)...);\n    ++end_;\n  }\n  else if (end_ != cap_)\n  {\n    auto new_end = end_;\n    data_allocator::construct(mystl::address_of(*end_), *(end_ - 1));\n    ++new_end;\n    mystl::copy_backward(xpos, end_ - 1, end_);\n    *xpos = value_type(mystl::forward<Args>(args)...);\n    end_ = new_end;\n  }\n  else\n  {\n    reallocate_emplace(xpos, mystl::forward<Args>(args)...);\n  }\n  return begin() + n;\n}\n\n// 在尾部就地构造元素，避免额外的复制或移动开销\ntemplate <class T>\ntemplate <class ...Args>\nvoid vector<T>::emplace_back(Args&& ...args)\n{\n  if (end_ < cap_)\n  {\n    data_allocator::construct(mystl::address_of(*end_), mystl::forward<Args>(args)...);\n    ++end_;\n  }\n  else\n  {\n    reallocate_emplace(end_, mystl::forward<Args>(args)...);\n  }\n}\n\n// 在尾部插入元素\ntemplate <class T>\nvoid vector<T>::push_back(const value_type& value)\n{\n  if (end_ != cap_)\n  {\n    data_allocator::construct(mystl::address_of(*end_), value);\n    ++end_;\n  }\n  else\n  {\n    reallocate_insert(end_, value);\n  }\n}\n\n// 弹出尾部元素\ntemplate <class T>\nvoid vector<T>::pop_back()\n{\n  MYSTL_DEBUG(!empty());\n  data_allocator::destroy(end_ - 1);\n  --end_;\n}\n\n// 在 pos 处插入元素\ntemplate <class T>\ntypename vector<T>::iterator\nvector<T>::insert(const_iterator pos, const value_type& value)\n{\n  MYSTL_DEBUG(pos >= begin() && pos <= end());\n  iterator xpos = const_cast<iterator>(pos);\n  const size_type n = pos - begin_;\n  if (end_ != cap_ && xpos == end_)\n  {\n    data_allocator::construct(mystl::address_of(*end_), value);\n    ++end_;\n  }\n  else if (end_ != cap_)\n  {\n    auto new_end = end_;\n    data_allocator::construct(mystl::address_of(*end_), *(end_ - 1));\n    ++new_end;\n    auto value_copy = value;  // 避免元素因以下复制操作而被改变\n    mystl::copy_backward(xpos, end_ - 1, end_);\n    *xpos = mystl::move(value_copy);\n    end_ = new_end;\n  }\n  else\n  {\n    reallocate_insert(xpos, value);\n  }\n  return begin_ + n;\n}\n\n// 删除 pos 位置上的元素\ntemplate <class T>\ntypename vector<T>::iterator\nvector<T>::erase(const_iterator pos)\n{\n  MYSTL_DEBUG(pos >= begin() && pos < end());\n  iterator xpos = begin_ + (pos - begin());\n  mystl::move(xpos + 1, end_, xpos);\n  data_allocator::destroy(end_ - 1);\n  --end_;\n  return xpos;\n}\n\n// 删除[first, last)上的元素\ntemplate <class T>\ntypename vector<T>::iterator\nvector<T>::erase(const_iterator first, const_iterator last)\n{\n  MYSTL_DEBUG(first >= begin() && last <= end() && !(last < first));\n  const auto n = first - begin();\n  iterator r = begin_ + (first - begin());\n  data_allocator::destroy(mystl::move(r + (last - first), end_, r), end_);\n  end_ = end_ - (last - first);\n  return begin_ + n;\n}\n\n// 重置容器大小\ntemplate <class T>\nvoid vector<T>::resize(size_type new_size, const value_type& value)\n{\n  if (new_size < size())\n  {\n    erase(begin() + new_size, end());\n  }\n  else\n  {\n    insert(end(), new_size - size(), value);\n  }\n}\n\n// 与另一个 vector 交换\ntemplate <class T>\nvoid vector<T>::swap(vector<T>& rhs) noexcept\n{\n  if (this != &rhs)\n  {\n    mystl::swap(begin_, rhs.begin_);\n    mystl::swap(end_, rhs.end_);\n    mystl::swap(cap_, rhs.cap_);\n  }\n}\n\n/*****************************************************************************************/\n// helper function\n\n// try_init 函数，若分配失败则忽略，不抛出异常\ntemplate <class T>\nvoid vector<T>::try_init() noexcept\n{\n  try\n  {\n    begin_ = data_allocator::allocate(16);\n    end_ = begin_;\n    cap_ = begin_ + 16;\n  }\n  catch (...)\n  {\n    begin_ = nullptr;\n    end_ = nullptr;\n    cap_ = nullptr;\n  }\n}\n\n// init_space 函数\ntemplate <class T>\nvoid vector<T>::init_space(size_type size, size_type cap)\n{\n  try\n  {\n    begin_ = data_allocator::allocate(cap);\n    end_ = begin_ + size;\n    cap_ = begin_ + cap;\n  }\n  catch (...)\n  {\n    begin_ = nullptr;\n    end_ = nullptr;\n    cap_ = nullptr;\n    throw;\n  }\n}\n\n// fill_init 函数\ntemplate <class T>\nvoid vector<T>::\nfill_init(size_type n, const value_type& value)\n{\n  const size_type init_size = mystl::max(static_cast<size_type>(16), n);\n  init_space(n, init_size);\n  mystl::uninitialized_fill_n(begin_, n, value);\n}\n\n// range_init 函数\ntemplate <class T>\ntemplate <class Iter>\nvoid vector<T>::\nrange_init(Iter first, Iter last)\n{\n  const size_type len = mystl::distance(first, last);\n  const size_type init_size = mystl::max(len, static_cast<size_type>(16));\n  init_space(len, init_size);\n  mystl::uninitialized_copy(first, last, begin_);\n}\n\n// destroy_and_recover 函数\ntemplate <class T>\nvoid vector<T>::\ndestroy_and_recover(iterator first, iterator last, size_type n)\n{\n  data_allocator::destroy(first, last);\n  data_allocator::deallocate(first, n);\n}\n\n// get_new_cap 函数\ntemplate <class T>\ntypename vector<T>::size_type \nvector<T>::\nget_new_cap(size_type add_size)\n{\n  const auto old_size = capacity();\n  THROW_LENGTH_ERROR_IF(old_size > max_size() - add_size,\n                        \"vector<T>'s size too big\");\n  if (old_size > max_size() - old_size / 2)\n  {\n    return old_size + add_size > max_size() - 16\n      ? old_size + add_size : old_size + add_size + 16;\n  }\n  const size_type new_size = old_size == 0\n    ? mystl::max(add_size, static_cast<size_type>(16))\n    : mystl::max(old_size + old_size / 2, old_size + add_size);\n  return new_size;\n}\n\n// fill_assign 函数\ntemplate <class T>\nvoid vector<T>::\nfill_assign(size_type n, const value_type& value)\n{\n  if (n > capacity())\n  {\n    vector tmp(n, value);\n    swap(tmp);\n  }\n  else if (n > size())\n  {\n    mystl::fill(begin(), end(), value);\n    end_ = mystl::uninitialized_fill_n(end_, n - size(), value);\n  }\n  else\n  {\n    erase(mystl::fill_n(begin_, n, value), end_);\n  }\n}\n\n// copy_assign 函数\ntemplate <class T>\ntemplate <class IIter>\nvoid vector<T>::\ncopy_assign(IIter first, IIter last, input_iterator_tag)\n{\n  auto cur = begin_;\n  for (; first != last && cur != end_; ++first, ++cur)\n  {\n    *cur = *first;\n  }\n  if (first == last)\n  {\n    erase(cur, end_);\n  }\n  else\n  {\n    insert(end_, first, last);\n  }\n}\n\n// 用 [first, last) 为容器赋值\ntemplate <class T>\ntemplate <class FIter>\nvoid vector<T>::\ncopy_assign(FIter first, FIter last, forward_iterator_tag)\n{\n  const size_type len = mystl::distance(first, last);\n  if (len > capacity())\n  {\n    vector tmp(first, last);\n    swap(tmp);\n  }\n  else if (size() >= len)\n  {\n    auto new_end = mystl::copy(first, last, begin_);\n    data_allocator::destroy(new_end, end_);\n    end_ = new_end;\n  }\n  else\n  {\n    auto mid = first;\n    mystl::advance(mid, size());\n    mystl::copy(first, mid, begin_);\n    auto new_end = mystl::uninitialized_copy(mid, last, end_);\n    end_ = new_end;\n  }\n}\n\n// 重新分配空间并在 pos 处就地构造元素\ntemplate <class T>\ntemplate <class ...Args>\nvoid vector<T>::\nreallocate_emplace(iterator pos, Args&& ...args)\n{\n  const auto new_size = get_new_cap(1);\n  auto new_begin = data_allocator::allocate(new_size);\n  auto new_end = new_begin;\n  try\n  {\n    new_end = mystl::uninitialized_move(begin_, pos, new_begin);\n    data_allocator::construct(mystl::address_of(*new_end), mystl::forward<Args>(args)...);\n    ++new_end;\n    new_end = mystl::uninitialized_move(pos, end_, new_end);\n  }\n  catch (...)\n  {\n    data_allocator::deallocate(new_begin, new_size);\n    throw;\n  }\n  destroy_and_recover(begin_, end_, cap_ - begin_);\n  begin_ = new_begin;\n  end_ = new_end;\n  cap_ = new_begin + new_size;\n}\n\n// 重新分配空间并在 pos 处插入元素\ntemplate <class T>\nvoid vector<T>::reallocate_insert(iterator pos, const value_type& value)\n{\n  const auto new_size = get_new_cap(1);\n  auto new_begin = data_allocator::allocate(new_size);\n  auto new_end = new_begin;\n  const value_type& value_copy = value;\n  try\n  {\n    new_end = mystl::uninitialized_move(begin_, pos, new_begin);\n    data_allocator::construct(mystl::address_of(*new_end), value_copy);\n    ++new_end;\n    new_end = mystl::uninitialized_move(pos, end_, new_end);\n  }\n  catch (...)\n  {\n    data_allocator::deallocate(new_begin, new_size);\n    throw;\n  }\n  destroy_and_recover(begin_, end_, cap_ - begin_);\n  begin_ = new_begin;\n  end_ = new_end;\n  cap_ = new_begin + new_size;\n}\n\n// fill_insert 函数\ntemplate <class T>\ntypename vector<T>::iterator \nvector<T>::\nfill_insert(iterator pos, size_type n, const value_type& value)\n{\n  if (n == 0)\n    return pos;\n  const size_type xpos = pos - begin_;\n  const value_type value_copy = value;  // 避免被覆盖\n  if (static_cast<size_type>(cap_ - end_) >= n)\n  { // 如果备用空间大于等于增加的空间\n    const size_type after_elems = end_ - pos;\n    auto old_end = end_;\n    if (after_elems > n)\n    {\n      mystl::uninitialized_copy(end_ - n, end_, end_);\n      end_ += n;\n      mystl::move_backward(pos, old_end - n, old_end);\n      mystl::uninitialized_fill_n(pos, n, value_copy);\n    }\n    else\n    {\n      end_ = mystl::uninitialized_fill_n(end_, n - after_elems, value_copy);\n      end_ = mystl::uninitialized_move(pos, old_end, end_);\n      mystl::uninitialized_fill_n(pos, after_elems, value_copy);\n    }\n  }\n  else\n  { // 如果备用空间不足\n    const auto new_size = get_new_cap(n);\n    auto new_begin = data_allocator::allocate(new_size);\n    auto new_end = new_begin;\n    try\n    {\n      new_end = mystl::uninitialized_move(begin_, pos, new_begin);\n      new_end = mystl::uninitialized_fill_n(new_end, n, value);\n      new_end = mystl::uninitialized_move(pos, end_, new_end);\n    }\n    catch (...)\n    {\n      destroy_and_recover(new_begin, new_end, new_size);\n      throw;\n    }\n    data_allocator::deallocate(begin_, cap_ - begin_);\n    begin_ = new_begin;\n    end_ = new_end;\n    cap_ = begin_ + new_size;\n  }\n  return begin_ + xpos;\n}\n\n// copy_insert 函数\ntemplate <class T>\ntemplate <class IIter>\nvoid vector<T>::\ncopy_insert(iterator pos, IIter first, IIter last)\n{\n  if (first == last)\n    return;\n  const auto n = mystl::distance(first, last);\n  if ((cap_ - end_) >= n)\n  { // 如果备用空间大小足够\n    const auto after_elems = end_ - pos;\n    auto old_end = end_;\n    if (after_elems > n)\n    {\n      end_ = mystl::uninitialized_copy(end_ - n, end_, end_);\n      mystl::move_backward(pos, old_end - n, old_end);\n      mystl::uninitialized_copy(first, last, pos);\n    }\n    else\n    {\n      auto mid = first;\n      mystl::advance(mid, after_elems);\n      end_ = mystl::uninitialized_copy(mid, last, end_);\n      end_ = mystl::uninitialized_move(pos, old_end, end_);\n      mystl::uninitialized_copy(first, mid, pos);\n    }\n  }\n  else\n  { // 备用空间不足\n    const auto new_size = get_new_cap(n);\n    auto new_begin = data_allocator::allocate(new_size);\n    auto new_end = new_begin;\n    try\n    {\n      new_end = mystl::uninitialized_move(begin_, pos, new_begin);\n      new_end = mystl::uninitialized_copy(first, last, new_end);\n      new_end = mystl::uninitialized_move(pos, end_, new_end);\n    }\n    catch (...)\n    {\n      destroy_and_recover(new_begin, new_end, new_size);\n      throw;\n    }\n    data_allocator::deallocate(begin_, cap_ - begin_);\n    begin_ = new_begin;\n    end_ = new_end;\n    cap_ = begin_ + new_size;\n  }\n}\n\n// reinsert 函数\ntemplate <class T>\nvoid vector<T>::reinsert(size_type size)\n{\n  auto new_begin = data_allocator::allocate(size);\n  try\n  {\n    mystl::uninitialized_move(begin_, end_, new_begin);\n  }\n  catch (...)\n  {\n    data_allocator::deallocate(new_begin, size);\n    throw;\n  }\n  data_allocator::deallocate(begin_, cap_ - begin_);\n  begin_ = new_begin;\n  end_ = begin_ + size;\n  cap_ = begin_ + size;\n}\n\n/*****************************************************************************************/\n// 重载比较操作符\n\ntemplate <class T>\nbool operator==(const vector<T>& lhs, const vector<T>& rhs)\n{\n  return lhs.size() == rhs.size() &&\n    mystl::equal(lhs.begin(), lhs.end(), rhs.begin());\n}\n\ntemplate <class T>\nbool operator<(const vector<T>& lhs, const vector<T>& rhs)\n{\n  return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());\n}\n\ntemplate <class T>\nbool operator!=(const vector<T>& lhs, const vector<T>& rhs)\n{\n  return !(lhs == rhs);\n}\n\ntemplate <class T>\nbool operator>(const vector<T>& lhs, const vector<T>& rhs)\n{\n  return rhs < lhs;\n}\n\ntemplate <class T>\nbool operator<=(const vector<T>& lhs, const vector<T>& rhs)\n{\n  return !(rhs < lhs);\n}\n\ntemplate <class T>\nbool operator>=(const vector<T>& lhs, const vector<T>& rhs)\n{\n  return !(lhs < rhs);\n}\n\n// 重载 mystl 的 swap\ntemplate <class T>\nvoid swap(vector<T>& lhs, vector<T>& rhs)\n{\n  lhs.swap(rhs);\n}\n\n} // namespace mystl\n#endif // !MYTINYSTL_VECTOR_H_\n\n"
  },
  {
    "path": "README.md",
    "content": "MyTinySTL\n=====\n[![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)\n\n## 简介\n   基于 `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) 改善代码，谢谢！\n\n## 支持\n\n* 操作系统\n  * linux\n  * windows\n  * osx\n* 编译器\n  * g++ 5.4 或以上\n  * clang++ 3.5 或以上\n  * msvc 14.0 或以上\n\n## 需要\n  * 使用 cmake 2.8 来构建项目（**可选**）\n\n## 运行\n\n如果你想要运行测试，请先阅读 [这个](https://github.com/Alinshans/MyTinySTL/blob/master/Test/README.md) 。\n\n  * gcc/clang on linux/osx\n  1. 克隆仓库\n```bash\n$ git clone git@github.com:Alinshans/MyTinySTL.git\n$ cd MyTinySTL\n```\n  2. 构建并运行\n```bash\n$ mkdir build && cd build\n$ cmake ..\n$ make\n$ cd ../bin && ./stltest\n```\n\n  * msvc on windows\n  1. 克隆仓库或 [Download ZIP](https://github.com/Alinshans/MyTinySTL/archive/master.zip)\n  2. 使用 `vs2015`（或 `vs2017`）打开 `MSVC/MyTinySTL_VS2015.sln`，配置成 `Release` 模式，（Ctrl + F5）开始执行。\n  \n## 文档\n  见 [Wiki](https://github.com/Alinshans/MyTinySTL/wiki)。\n\n## 测试\n  见 [Test](https://github.com/Alinshans/MyTinySTL/tree/master/Test)。\n\n---\n\n## Introduction\n\nThis 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!\n\n## Supported\n\n* os\n  * linux\n  * windows\n  * osx\n* complier\n  * g++ 5.4 or later\n  * clang++ 3.5 or later\n  * msvc 14.0 or later\n\n## Required\n\n* Use cmake 2.8 to build this project (**Optional**)\n\n## Run test\n\nIf you want to run the test, please read [this](https://github.com/Alinshans/MyTinySTL/blob/master/Test/README.md) first.\n\n* gcc/clang on linux/osx\n\n1. git clone\n```bash\n$ git clone git@github.com:Alinshans/MyTinySTL.git\n$ cd MyTinySTL\n```\n2. build and run\n```bash\n$ mkdir build && cd build\n$ cmake ..\n$ make\n$ cd ../bin && ./stltest\n```\n\n* msvc on windows\n\n1. git clone or [Download ZIP](https://github.com/Alinshans/MyTinySTL/archive/master.zip)\n2. use `vs2015`(or `vs2017`) open the file `MSVC/MyTinySTL_VS2015.sln`, configured in `Release`, run this project(Ctrl + F5).\n\n## Documents\n\nSee [Wiki](https://github.com/Alinshans/MyTinySTL/wiki).\n\n## Test\n\nSee [Test](https://github.com/Alinshans/MyTinySTL/tree/master/Test).\n"
  },
  {
    "path": "Test/CMakeLists.txt",
    "content": "include_directories(${PROJECT_SOURCE_DIR}/MyTinySTL)\nset(APP_SRC test.cpp)\nset(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)\nadd_executable(stltest ${APP_SRC})"
  },
  {
    "path": "Test/Lib/redbud/io/color.h",
    "content": "// ============================================================================\n// Copyright (c) 2017 Alinshans. All rights reserved.\n// Licensed under the MIT License. See LICENSE for details.\n// \n// Header File : redbud/io/color.h \n//\n// This file is used to control font format and color in the terminal, which\n// refers to a project on github, see https://github.com/agauniyal/rang .\n// ============================================================================\n\n#ifndef ALINSHANS_REDBUD_IO_COLOR_H_\n#define ALINSHANS_REDBUD_IO_COLOR_H_\n\n#include \"../platform.h\"\n\n#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)\n  #include <unistd.h>  // getenv\n  #include <cstring>   // strstr\n#elif defined(REDBUD_WIN)\n  #include <Windows.h>\n  #include <io.h>\n#endif\n\n#include <cstdlib>\n#include <iostream>\n#include <type_traits>\n\nnamespace redbud\n{\nnamespace io\n{\n\n// ============================================================================\n// Enumerates the ANSI escape code corresponding to the font attributes.\n// See https://en.wikipedia.org/wiki/ANSI_escape_code for details.\n//\n// Example:\n//   using namespace redbud::io;\n//   std::cout << fg::red << \"This text has a red foreground color\\n\";\n//   std::cout << bg::green << \"This text has a green background color\\n\"\n// ============================================================================\n\n// Sets the text format, some of them is not widely supported.\nenum class format\n{\n  reset      = 0,  // All attributes off.\n  bold       = 1,  // Bold or increased intensity.\n  faint      = 2,  // Faint (decreased intensity).\n  italic     = 3,  // Italian font.\n  underline  = 4,  // Underline.\n  blinkslow  = 5,  // Blink slowly.\n  blinkrapid = 6,  // Blink quickly.\n  inverse    = 7,  // Swap foreground and background.\n  conceal    = 8,  // Hide the text.\n  strikeline = 9   // Characters legible, but marked for deletion.\n};\n\n// Sets the foreground color.\nenum class fg\n{\n  black   = 30,\n  red     = 31,\n  green   = 32,\n  yellow  = 33,\n  blue    = 34,\n  purple  = 35,\n  cyan    = 36,\n  white   = 37,\n  reserve = 38,\n  reset   = 39\n};\n\n// Sets the background color.\nenum class bg\n{\n  black   = 40,\n  red     = 41,\n  green   = 42,\n  yellow  = 43,\n  blue    = 44,\n  purple  = 45,\n  cyan    = 46,\n  white   = 47,\n  reserve = 38,\n  reset   = 39\n};\n\n// Sets the highlight foreground color.\nenum class hfg\n{\n  black  = 90,\n  red    = 91,\n  green  = 92,\n  yellow = 93,\n  blue   = 94,\n  purple = 95,\n  cyan   = 96,\n  white  = 97\n};\n\n// Sets the highlight background color.\nenum class hbg\n{\n  black  = 100,\n  red    = 101,\n  green  = 102,\n  yellow = 103,\n  blue   = 104,\n  purple = 105,\n  cyan   = 106,\n  white  = 107\n};\n\n// Sets the control state.\nenum class state\n{\n  automatic = 0,  // Automatic control.\n  manual    = 1   // Manual control.\n};\n\n// ----------------------------------------------------------------------------\n// Details\nnamespace details\n{\n\n// Manages associated stream buffer.\ninline const std::streambuf*& get_coutbuf()\n{\n  static const std::streambuf* pout = std::cout.rdbuf();\n  return pout;\n}\n\ninline const std::streambuf*& get_cerrbuf()\n{\n  static const std::streambuf* perr = std::cerr.rdbuf();\n  return perr;\n}\n\ninline const std::streambuf*& get_clogbuf()\n{\n  static const std::streambuf* plog = std::clog.rdbuf();\n  return plog;\n}\n\n// Gets an unique integer to use as index to iword()\ninline int get_iword()\n{\n  static int i = std::ios_base::xalloc();\n  return i;\n}\n\n// Determines whether the terminal color of this system can be modified.\ninline bool is_modifiable()\n{\n#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)\n  static constexpr const char* terms[] = {\n    \"ansi\", \"color\", \"console\", \"cygwin\", \"gnome\", \"konsole\", \"kterm\",\n    \"linux\", \"msys\", \"putty\", \"rxvt\", \"screen\", \"vt100\", \"xterm\"\n  };\n  const char *penv = std::getenv(\"TERM\");\n  if (penv == nullptr)\n  {\n    return false;\n  }\n  bool result = false;\n  for (const auto& t : terms)\n  {\n    if (std::strstr(penv, t) != nullptr)\n    {\n      result = true;\n      break;\n    }\n  }\n\n#elif defined(REDBUD_WIN)\n  static constexpr bool result = true;\n#endif\n  return result;\n}\n\n/// Determines whether the buffer stream reaches the end.\ninline bool is_terminal(const std::streambuf* buf)\n{\n  if (buf == get_coutbuf())\n  {\n#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)\n    return isatty(fileno(stdout)) ? true : false;\n#elif defined(REDBUD_WIN)\n    return _isatty(_fileno(stdout)) ? true : false;\n#endif\n  }\n\n  if (buf == get_cerrbuf() || buf == get_clogbuf())\n  {\n#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)\n    return isatty(fileno(stderr)) ? true : false;\n#elif defined(REDBUD_WIN)\n    return _isatty(_fileno(stderr)) ? true : false;\n#endif\n  }\n  return false;\n}\n\n// For overloading standard output stream.\ntemplate <typename T>\nusing color_return_t = typename std::enable_if<\n  std::is_same<T, redbud::io::format>::value ||\n  std::is_same<T, redbud::io::fg>::value ||\n  std::is_same<T, redbud::io::bg>::value ||\n  std::is_same<T, redbud::io::hfg>::value ||\n  std::is_same<T, redbud::io::hbg>::value,\n  std::ostream&>::type;\n\ntemplate <typename T>\nusing state_return_t = typename std::enable_if<\n  std::is_same<T, redbud::io::state>::value,\n  std::ostream&>::type;\n\n// Sets the format and color of the text.\n#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)\ntemplate <typename T>\ninline color_return_t<T> set_color(std::ostream& os, const T& value)\n{\n  return os << \"\\033[\" << static_cast<int>(value) << \"m\";\n}\n\n#elif defined(REDBUD_WIN)\n\nstatic constexpr WORD default_state = (FOREGROUND_BLUE | \n                                       FOREGROUND_GREEN |\n                                       FOREGROUND_RED);\n\n// Gets the corresponding RGB value on Windows.\ninline WORD get_rgb(WORD rgb)\n{\n  static constexpr WORD cor[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };\n  return cor[rgb];\n}\n\n// Sets font attributes on Windows.\ninline void set_attributes(redbud::io::fg color, WORD& state)\n{\n  if (color == redbud::io::fg::reserve)\n  {\n    return;\n  }\n  state &= 0xFFF0;\n  if (color == redbud::io::fg::reset)\n  {\n    state |= default_state;\n    return;\n  }\n  state |= get_rgb(static_cast<WORD>(color) - 30);\n}\n\ninline void set_attributes(redbud::io::bg color, WORD& state)\n{\n  if (color == redbud::io::bg::reserve)\n  {\n    return;\n  }\n  state &= 0xFF0F;\n  if (color == redbud::io::bg::reset)\n  {\n    return;\n  }\n  state |= get_rgb(static_cast<WORD>(color) - 40) << 4;\n}\n\ninline void set_attributes(redbud::io::hfg color, WORD& state)\n{\n  state &= 0xFFF0;\n  state |= (static_cast<WORD>(0x8) | \n            get_rgb(static_cast<WORD>(color) - 90));\n}\n\ninline void set_attributes(redbud::io::hbg color, WORD& state)\n{\n  state &= 0xFF0F;\n  state |= (static_cast<WORD>(0x80) | \n            get_rgb(static_cast<WORD>(color) - 100) << 4);\n}\n\ninline void set_attributes(redbud::io::format format, WORD& state)\n{\n  if (format == redbud::io::format::reset)\n  {\n    state = default_state;\n  }\n}\n\ninline WORD& current_state()\n{\n  static WORD state = default_state;\n  return state;\n}\n\ninline HANDLE get_console_handle()\n{\n  static HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);\n  return h;\n}\n\ntemplate <typename T>\ninline color_return_t<T> set_color(std::ostream& os, const T& value)\n{\n  HANDLE h = get_console_handle();\n  if (h && is_terminal(os.rdbuf()))\n  {\n    set_attributes(value, current_state());\n    SetConsoleTextAttribute(h, current_state());\n    return os;\n  }\n  return os;\n}\n#endif\n\n} // namespace details\n\n// ----------------------------------------------------------------------------\n// Overloads standard output stream to control the color of text.\n\ntemplate <typename T>\ninline details::color_return_t<T> \noperator<<(std::ostream& os, const T& value)\n{\n  return (os.iword(details::get_iword()) ||\n         (details::is_modifiable() &&\n         details::is_terminal(os.rdbuf())))\n    ? details::set_color(os, value)\n    : os;\n}\n\ntemplate <typename T>\ninline details::state_return_t<T> \noperator<<(std::ostream& os, const T& value)\n{\n  if (value == redbud::io::state::automatic)\n  {\n    os.iword(details::get_iword()) = 0;\n  }\n  else if (value == redbud::io::state::manual)\n  {\n    os.iword(details::get_iword()) = 1;\n  }\n  return os;\n}\n\n} // namespace io\n} // namespace redbud\n#endif // !ALINSHANS_REDBUD_IO_COLOR_H_\n"
  },
  {
    "path": "Test/Lib/redbud/platform.h",
    "content": "// ============================================================================\n// Copyright (c) 2017 Alinshans. All rights reserved.\n// Licensed under the MIT License. See LICENSE for details.\n// \n// Header File : redbud/platform.h\n//\n// This file contains some preprocessing macros related to the platform.\n// ============================================================================\n\n#ifndef ALINSHANS_REDBUD_PLATFORM_H_\n#define ALINSHANS_REDBUD_PLATFORM_H_\n\n// ----------------------------------------------------------------------------\n// os\n\n#if defined(WIN32) || defined(_WIN32) || defined(_WIN64)\n  #define REDBUD_WIN 1\n#elif defined(__unix__) || defined(__unix) || defined(__linux__)\n  #define REDBUD_LINUX 1\n#elif defined(__APPLE__) || defined(__MACH__)\n  #define REDBUD_OSX 1\n#else\n  #error \"System that is not supported yet.\"\n#endif\n\n// ----------------------------------------------------------------------------\n// complier\n\n#if defined(__clang__)\n  #define REDBUD_CLANG __clang__\n#elif defined(__GNUC__)\n  #define REDBUD_GNUC __GNUC__\n#elif defined(_MSC_VER)\n  #define REDBUD_MSVC _MSC_VER\n#else\n  #error \"Complier that is not supported yet.\"\n#endif\n\n// ----------------------------------------------------------------------------\n// stringify\n\n#define REDBUD_TO_STRING(x) #x\n#define REDBUD_STRING(x) REDBUD_TO_STRING(x)\n\n// ----------------------------------------------------------------------------\n// join\n\n#define REDBUD_DO_JOIN(x ,y) x##y\n#define REDBUD_JOIN(x, y) REDBUD_DO_JOIN(x, y)\n\n// ----------------------------------------------------------------------------\n// version\n\n#define REDBUD_MAJOR 1\n#define REDBUD_MINOR 0\n#define REDBUD_PATCH 0\n#define REDBUD_VERSION \\\n  REDBUD_STRING(REDBUD_MAJOR.REDBUD_MINOR.REDBUD_PATCH)\n\n#define _VERSION_CODE(x,y,z) \\\n  (((x)*100000) + ((y)*100) + (z))\n\n#define GNUC_VERSION \\\n  _VERSION_CODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n\n#define CLANG_VERSION \\\n  _VERSION_CODE(__clang_major__, __clang_minor__, __clang_patchlevel__)\n\n// ----------------------------------------------------------------------------\n// redbud API\n\n#ifndef _REDBUD_API\n  #define _REDBUD_API ::redbud::\n#endif\n\n// ----------------------------------------------------------------------------\n// C++11 required\n\n#ifndef REDBUD_HAS_CXX11\n  #if defined(REDBUD_MSVC) && (REDBUD_MSVC >= 1900)\n    #define REDBUD_HAS_CXX11 1\n  #elif defined(REDBUD_GNUC) && (GNUC_VERSION >= _VERSION_CODE(4,8,0)) && \\\n  defined(__GXX_EXPERIMENTAL_CXX0X__)\n    #define REDBUD_HAS_CXX11 1\n  #elif defined(REDBUD_CLANG) && (CLANG_VERSION >= _VERSION_CODE(3,3,0))\n    #define REDBUD_HAS_CXX11 1\n  #else \n    #define REDBUD_HAS_CXX11 0\n  #endif\n#endif // !REDBUD_HAS_CXX11\n\n#if REDBUD_HAS_CXX11 == 0\n  #error \"C++11 required.\"\n#endif\n\n// ----------------------------------------------------------------------------\n// Undefines macro min and max in MSVC.\n\nnamespace redbud\n{\n\n#if REDBUD_MSVC\n  #define NOMINMAX\n#endif\n\n}\n\n#endif // !ALINSHANS_REDBUD_PLATFORM_H_\n"
  },
  {
    "path": "Test/README.md",
    "content": "单元测试 (Unit test)\n=====\n## 测试环境 (Test environment)\n  测试直接在 `Travis CI` 和 `AppVeyor` 上构建并运行，已在以下环境中做过测试：\n  \n  Tests were built and run directly on `Tracis CI` and `AppVeyor` and had been tested in the following environments:\n\n  * linux, ubuntu 14.04, gcc5/6/7\n  * osx, xcode5/6/7/8\n  * windows, VS2015/VS2017, [x64|x86], [Release|Debug]\n  \n## 测试框架 (Test frame)\n  在 [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h) 中，用了两个类实现了一个简单的测试框架，并定义了大量宏来封装测试过程。</br>\n  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.\n  \n## 测试内容 (Test content)\n  在 [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>\n  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.**\n\n  测试案例如下：<br>\n  The test cases are as follows:\n\n  * [algorithm](https://github.com/Alinshans/MyTinySTL/blob/master/Test/algorithm_test.h) *(100%/100%)*\n  * [algorithm_performance](https://github.com/Alinshans/MyTinySTL/blob/master/Test/algorithm_performance_test.h) *(100%/100%)*\n  * [deque](https://github.com/Alinshans/MyTinySTL/blob/master/Test/deque_test.h) *(100%/100%)*\n  * [list](https://github.com/Alinshans/MyTinySTL/blob/master/Test/list_test.h) *(100%/100%)*\n  * [map](https://github.com/Alinshans/MyTinySTL/blob/master/Test/map_test.h) *(100%/100%)*\n    * map\n    * multimap\n  * [queue](https://github.com/Alinshans/MyTinySTL/blob/master/Test/queue_test.h) *(100%/100%)*\n    * queue\n    * priority_queue\n  * [set](https://github.com/Alinshans/MyTinySTL/blob/master/Test/set_test.h) *(100%/100%)*\n    * set\n    * multiset\n  * [stack](https://github.com/Alinshans/MyTinySTL/blob/master/Test/stack_test.h) *(100%/100%)*\n  * [string_test](https://github.com/Alinshans/MyTinySTL/blob/master/Test/string_test.h) *(100%/100%)*\n  * [unordered_map](https://github.com/Alinshans/MyTinySTL/blob/master/Test/unordered_map_test.h) *(100%/100%)*\n    * unordered_map\n    * unordered_multimap\n  * [unordered_set](https://github.com/Alinshans/MyTinySTL/blob/master/Test/unordered_set_test.h) *(100%/100%)*\n    * unordered_set\n    * unordered_multiset\n  * [vector](https://github.com/Alinshans/MyTinySTL/blob/master/Test/vector_test.h) *(100%/100%)*\n  \n  \n## 测试结果 (Test result)\n  见 [Travis CI](https://travis-ci.org/Alinshans/MyTinySTL) 和 [AppVeyor](https://ci.appveyor.com/project/Alinshans/mytinystl)。\n\n  See [Travis CI](https://travis-ci.org/Alinshans/MyTinySTL) and [AppVeyor](https://ci.appveyor.com/project/Alinshans/mytinystl).\n  \n"
  },
  {
    "path": "Test/algorithm_performance_test.h",
    "content": "﻿#ifndef MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_\n#define MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_\n\n// 仅仅针对 sort, binary_search 做了性能测试\n\n#include <algorithm>\n\n#include \"../MyTinySTL/algorithm.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace algorithm_performance_test\n{\n\n// 函数性能测试宏定义\n#define FUN_TEST1(mode, fun, count) do {                      \\\n    std::string fun_name = #fun;                               \\\n    srand((int)time(0));                                       \\\n    char buf[10];                                              \\\n    clock_t start, end;                                        \\\n    int *arr = new int[count];                                 \\\n    for(size_t i = 0; i < count; ++i)  *(arr + i) = rand();    \\\n    start = clock();                                           \\\n    mode::fun(arr, arr + count);                               \\\n    end = clock();                                             \\\n    int n = static_cast<int>(static_cast<double>(end - start)  \\\n        / CLOCKS_PER_SEC * 1000);                              \\\n    std::snprintf(buf, sizeof(buf), \"%d\", n);                  \\\n    std::string t = buf;                                       \\\n    t += \"ms   |\";                                             \\\n    std::cout << std::setw(WIDE) << t;                         \\\n    delete []arr;                                              \\\n} while(0)\n\n#define FUN_TEST2(mode, fun, count) do {                      \\\n    std::string fun_name = #fun;                               \\\n    srand((int)time(0));                                       \\\n    char buf[10];                                              \\\n    clock_t start, end;                                        \\\n    int *arr = new int[count];                                 \\\n    for(size_t i = 0; i < count; ++i)  *(arr + i) = rand();    \\\n    start = clock();                                           \\\n    for(size_t i = 0; i < count; ++i)                          \\\n        mode::fun(arr, arr + count, rand());                   \\\n    end = clock();                                             \\\n    int n = static_cast<int>(static_cast<double>(end - start)  \\\n        / CLOCKS_PER_SEC * 1000);                              \\\n    std::snprintf(buf, sizeof(buf), \"%d\", n);                  \\\n    std::string t = buf;                                       \\\n    t += \"ms   |\";                                             \\\n    std::cout << std::setw(WIDE) << t;                         \\\n    delete []arr;                                              \\\n} while(0)\n\nvoid binary_search_test()\n{\n  std::cout << \"[------------------- function : binary_search ------------------]\" << std::endl;\n  std::cout << \"| orders of magnitude |\";\n  TEST_LEN(LEN1, LEN2, LEN3, WIDE);\n  std::cout << \"|         std         |\";\n  FUN_TEST2(std, binary_search, LEN1);\n  FUN_TEST2(std, binary_search, LEN2);\n  FUN_TEST2(std, binary_search, LEN3);\n  std::cout << std::endl << \"|        mystl        |\";\n  FUN_TEST2(mystl, binary_search, LEN1);\n  FUN_TEST2(mystl, binary_search, LEN2);\n  FUN_TEST2(mystl, binary_search, LEN3);\n  std::cout << std::endl;\n}\n\nvoid sort_test()\n{\n  std::cout << \"[----------------------- function : sort -----------------------]\" << std::endl;\n  std::cout << \"| orders of magnitude |\";\n  TEST_LEN(LEN1, LEN2, LEN3, WIDE);\n  std::cout << \"|         std         |\";\n  FUN_TEST1(std, sort, LEN1);\n  FUN_TEST1(std, sort, LEN2);\n  FUN_TEST1(std, sort, LEN3);\n  std::cout << std::endl << \"|        mystl        |\";\n  FUN_TEST1(mystl, sort, LEN1);\n  FUN_TEST1(mystl, sort, LEN2);\n  FUN_TEST1(mystl, sort, LEN3);\n  std::cout << std::endl;\n}\n\nvoid algorithm_performance_test()\n{\n\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[--------------- Run algorithm performance test ----------------]\" << std::endl;\n  sort_test();\n  binary_search_test();\n  std::cout << \"[--------------- End algorithm performance test ----------------]\" << std::endl;\n  std::cout << \"[===============================================================]\" << std::endl;\n#endif // PERFORMANCE_TEST_ON\n\n}\n\n} // namespace algorithm_performance_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_\n\n"
  },
  {
    "path": "Test/algorithm_test.h",
    "content": "#ifndef MYTINYSTL_ALGORITHM_TEST_H_\n#define MYTINYSTL_ALGORITHM_TEST_H_\n\n// 算法测试: 包含了 mystl 的 81 个算法测试\n\n#include <algorithm>\n#include <functional>\n#include <numeric>\n\n#include \"../MyTinySTL/algorithm.h\"\n#include \"../MyTinySTL/vector.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\n\n#ifdef max\n#pragma message(\"#undefing marco max\")\n#undef max\n#endif // max\n\n#ifdef min\n#pragma message(\"#undefing marco min\")\n#undef min\n#endif // min\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable: 4389)\n#endif // _MSC_VER\n\nnamespace algorithm_test\n{\n\n// 一些可能会用到的辅助数据和函数\nint  for_each_sum = 0;\n\nint  gen() { return 5; }\nint  r(int i) { return (i * 5 + 1) % 9; }\nbool is_odd(int i) { return i & 1; }\nbool is_even(int i) { return !(i & 1); }\nvoid arr_sum(int i) { for_each_sum += i; }\nbool cmp(const int& a, const int& b) { return b < a; }\nint  unary_op(const int& x) { return x + 1; }\nint  binary_op(const int& x, const int& y) { return x + y; }\n\n// 以下为 80 个函数的简单测试\n\n// algobase test:\nTEST(copy_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };\n  int exp[5], act[5];\n  std::copy(arr1, arr1 + 5, exp);\n  mystl::copy(arr1, arr1 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::copy(arr1 + 5, arr1 + 10, exp);\n  mystl::copy(arr1 + 5, arr1 + 10, act);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(copy_backward_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  std::vector<int> exp{ 0,0,0,0,0,6,7,8,9,10 };\n  int act[] = { 0,0,0,0,0,6,7,8,9,10 };\n  std::copy_backward(arr1, arr1 + 5, exp.begin() + 5);\n  mystl::copy_backward(arr1, arr1 + 5, act + 5);\n  EXPECT_CON_EQ(exp, act);\n  std::copy_backward(exp.begin(), exp.begin() + 8, exp.begin() + 9);\n  mystl::copy_backward(act, act + 8, act + 9);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(copy_if_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };\n  int exp[5], act[5];\n  std::copy_if(arr1, arr1 + 10, exp, is_odd);\n  mystl::copy_if(arr1, arr1 + 10, act, is_odd);\n  EXPECT_CON_EQ(exp, act);\n  std::copy_if(arr1, arr1 + 10, exp, is_even);\n  mystl::copy_if(arr1, arr1 + 10, act, is_even);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(copy_n_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };\n  int exp[10], act[10];\n  std::copy_n(arr1, 10, exp);\n  mystl::copy_n(arr1, 10, act);\n  EXPECT_CON_EQ(exp, act);\n  std::copy_n(arr1 + 5, 5, exp);\n  mystl::copy_n(arr1 + 5, 5, act);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(move_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 1,2,3,4,5 };\n  int exp[5], act[5];\n  std::move(arr1, arr1 + 5, exp);\n  mystl::move(arr2, arr2 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(move_backward_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 1,2,3,4,5 };\n  int exp[5], act[5];\n  std::move_backward(arr1, arr1 + 5, exp + 5);\n  mystl::move_backward(arr2, arr2 + 5, act + 5);\n  EXPECT_CON_EQ(exp, act);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(equal_test)\n{\n  std::vector<int> v1{ 1,2,3,4,5 };\n  std::vector<int> v2{ 1,2,3,4,5,6 };\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 1,2,3,4,6 };\n  EXPECT_EQ(std::equal(v1.begin(), v1.end(), v2.begin()),\n            mystl::equal(v1.begin(), v1.end(), v2.begin()));\n  EXPECT_EQ(std::equal(arr1, arr1 + 5, arr2),\n            mystl::equal(arr1, arr1 + 5, arr2));\n  EXPECT_EQ(std::equal(v1.begin(), v1.end(), arr1),\n            mystl::equal(v1.begin(), v1.end(), arr1));\n  EXPECT_EQ(std::equal(v1.begin(), v1.end(), arr2, std::equal_to<int>()),\n            mystl::equal(v1.begin(), v1.end(), arr2, std::equal_to<int>()));\n}\n\nTEST(fill_test)\n{\n  int exp[10], act[10];\n  mystl::vector<int> v1(10, 1);\n  mystl::vector<int> v2(10, 2);\n  std::fill(exp, exp + 10, 1);\n  mystl::fill(act, act + 10, 1);\n  EXPECT_CON_EQ(exp, act);\n  std::fill(v1.begin(), v1.end(), 3);\n  mystl::fill(v2.begin(), v2.end(), 3);\n  EXPECT_CON_EQ(v1, v2);\n}\n\nTEST(fill_n_test)\n{\n  int arr1[5];\n  int arr2[5];\n  std::fill_n(arr2, 5, 1);\n  mystl::fill_n(arr1, 5, 1);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::fill_n(arr1 + 2, 3, 2);\n  mystl::fill_n(arr2 + 2, 3, 2);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(iter_swap_test)\n{\n  int a = 1;\n  int b = 2;\n  int *p1 = &a;\n  int *p2 = &b;\n  int *p3 = &a;\n  int *p4 = &b;\n  std::iter_swap(p1, p2);\n  mystl::iter_swap(p3, p4);\n  EXPECT_PTR_EQ(p1, p3);\n  EXPECT_PTR_EQ(p2, p4);\n  EXPECT_EQ(p1, p3);\n  EXPECT_EQ(p2, p4);\n}\n\nTEST(lexicographical_compare_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 0,2,4,6,8 };\n  int arr3[] = { 1,2,3,4,5 };\n  int arr4[] = { 1,2,3,4,5,6 };\n  int arr5[] = { 2,3,4 };\n  EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr2, arr2 + 5),\n            mystl::lexicographical_compare(arr1, arr1 + 5, arr2, arr2 + 5));\n  EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr3, arr3 + 5),\n            mystl::lexicographical_compare(arr1, arr1 + 5, arr3, arr3 + 5));\n  EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr4, arr4 + 6, std::less<int>()),\n            mystl::lexicographical_compare(arr1, arr1 + 5, arr4, arr4 + 6, std::less<int>()));\n  EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr5, arr5 + 3, std::less<int>()),\n            mystl::lexicographical_compare(arr1, arr1 + 5, arr5, arr5 + 3, std::less<int>()));\n}\n\nTEST(max_test)\n{\n  int i1 = 1, i2 = 2;\n  double d1 = 1.1, d2 = 2.2;\n  char c1 = 'a', c2 = 'b';\n  EXPECT_EQ(std::max(i1, i2), mystl::max(i1, i2));\n  EXPECT_EQ(std::max(d1, d2), mystl::max(d1, d2));\n  EXPECT_EQ(std::max(c1, c2), mystl::max(c1, c2));\n}\n\nTEST(min_test)\n{\n  int i1 = 1, i2 = 2;\n  double d1 = 1.1, d2 = 2.2;\n  char c1 = 'a', c2 = 'b';\n  EXPECT_EQ(std::min(i1, i2), mystl::min(i1, i2));\n  EXPECT_EQ(std::min(d1, d2), mystl::min(d1, d2));\n  EXPECT_EQ(std::min(c1, c2), mystl::min(c1, c2));\n}\n\nTEST(mismatch_test)\n{\n  int arr1[] = { 1,1,2,2,3,4,5 };\n  int arr2[] = { 1,1,2,2,3,3,3 };\n  int arr3[] = { 0,1,2,2,3,4,5 };\n  int arr4[] = { 1,1,2,2,3,4,5 };\n  auto p1 = std::mismatch(arr1, arr1 + 7, arr2);\n  auto p2 = mystl::mismatch(arr1, arr1 + 7, arr2);\n  auto p3 = std::mismatch(arr1, arr1 + 7, arr3);\n  auto p4 = mystl::mismatch(arr1, arr1 + 7, arr3);\n  auto p5 = std::mismatch(arr1, arr1 + 7, arr4, std::equal_to<int>());\n  auto p6 = mystl::mismatch(arr1, arr1 + 7, arr4, std::equal_to<int>());\n  EXPECT_EQ(p1.first, p2.first);\n  EXPECT_EQ(p1.second, p2.second);\n  EXPECT_EQ(p3.first, p4.first);\n  EXPECT_EQ(p3.second, p4.second);\n  EXPECT_EQ(p5.first, p6.first);\n  EXPECT_EQ(p5.second, p6.second);\n}\n\n// heap_algo test\nTEST(make_heap_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr3[] = { 2,1,6,5,4,9,8,7,6 };\n  int arr4[] = { 2,1,6,5,4,9,8,7,6 };\n  int arr5[] = { 1,1,2,2,3,3,4,4,5,5 };\n  int arr6[] = { 1,1,2,2,3,3,4,4,5,5 };\n  std::make_heap(arr1, arr1 + 9);\n  mystl::make_heap(arr2, arr2 + 9);\n  std::make_heap(arr3, arr3 + 9);\n  mystl::make_heap(arr4, arr4 + 9);\n  std::make_heap(arr5, arr5 + 10, std::greater<int>());\n  mystl::make_heap(arr6, arr6 + 10, std::greater<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n  EXPECT_CON_EQ(arr3, arr4);\n  EXPECT_CON_EQ(arr5, arr6);\n}\n\nTEST(pop_heap_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  std::make_heap(arr1, arr1 + 9);\n  std::make_heap(arr2, arr2 + 9);\n  for (int i = 9; i > 0; --i)\n  {\n    std::pop_heap(arr1, arr1 + i);\n    mystl::pop_heap(arr2, arr2 + i);\n    EXPECT_CON_EQ(arr1, arr2);\n  }\n  int arr3[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr4[] = { 1,2,3,4,5,6,7,8,9 };\n  std::make_heap(arr3, arr3 + 9, std::greater<int>());\n  std::make_heap(arr4, arr4 + 9, std::greater<int>());\n  std::pop_heap(arr3, arr3 + 9, std::greater<int>());\n  mystl::pop_heap(arr4, arr4 + 9, std::greater<int>());\n  EXPECT_CON_EQ(arr3, arr4);\n}\n\nTEST(push_heap_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  std::make_heap(arr1, arr1 + 4);\n  std::make_heap(arr2, arr2 + 4);\n  for (int i = 4; i <= 9; ++i)\n  {\n    std::push_heap(arr1, arr1 + i);\n    mystl::push_heap(arr2, arr2 + i);\n    EXPECT_CON_EQ(arr1, arr2);\n  }\n  int arr3[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr4[] = { 1,2,3,4,5,6,7,8,9 };\n  std::make_heap(arr3, arr3 + 9, std::greater<int>());\n  std::make_heap(arr4, arr4 + 9, std::greater<int>());\n  std::push_heap(arr3, arr3 + 9, std::greater<int>());\n  mystl::push_heap(arr4, arr4 + 9, std::greater<int>());\n  EXPECT_CON_EQ(arr3, arr4);\n}\n\nTEST(sort_heap_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr3[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr4[] = { 1,2,3,4,5,6,7,8,9 };\n  std::make_heap(arr1, arr1 + 9);\n  std::make_heap(arr2, arr2 + 9);\n  std::make_heap(arr3, arr3 + 9, std::greater<int>());\n  std::make_heap(arr4, arr4 + 9, std::greater<int>());\n  std::sort_heap(arr1, arr1 + 9);\n  mystl::sort_heap(arr2, arr2 + 9);\n  std::sort_heap(arr3, arr3 + 9, std::greater<int>());\n  mystl::sort_heap(arr4, arr4 + 9, std::greater<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n  EXPECT_CON_EQ(arr3, arr4);\n}\n\n// set_algo test\nTEST(set_difference_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6 };\n  int arr3[] = { 1,2,3 };\n  int exp[6] = { 0 }, act[6] = { 0 };\n  std::set_difference(arr1, arr1 + 9, arr2, arr2 + 6, exp);\n  mystl::set_difference(arr1, arr1 + 9, arr2, arr2 + 6, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_difference(arr2, arr2 + 6, arr3, arr3 + 3, exp);\n  mystl::set_difference(arr2, arr2 + 6, arr3, arr3 + 3, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_difference(arr1, arr1 + 9, arr3, arr3 + 3, exp, std::less<int>());\n  mystl::set_difference(arr1, arr1 + 9, arr3, arr3 + 3, act, std::less<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(set_intersection_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6 };\n  int arr3[] = { 1,2,3 };\n  int exp[9] = { 0 }, act[9] = { 0 };\n  std::set_intersection(arr1, arr1 + 9, arr2, arr2 + 6, exp);\n  mystl::set_intersection(arr1, arr1 + 9, arr2, arr2 + 6, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_intersection(arr2, arr2 + 6, arr3, arr3 + 3, exp);\n  mystl::set_intersection(arr2, arr2 + 6, arr3, arr3 + 3, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_intersection(arr1, arr1 + 9, arr3, arr3 + 3, exp, std::less<int>());\n  mystl::set_intersection(arr1, arr1 + 9, arr3, arr3 + 3, act, std::less<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(set_symmetric_difference_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 1,3,5,7,9 };\n  int arr3[] = { 2,4,6,8,10 };\n  int exp[10] = { 0 }, act[10] = { 0 };\n  std::set_symmetric_difference(arr1, arr1 + 5, arr2, arr2 + 5, exp);\n  mystl::set_symmetric_difference(arr1, arr1 + 5, arr2, arr2 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_symmetric_difference(arr1, arr1 + 5, arr3, arr3 + 5, exp);\n  mystl::set_symmetric_difference(arr1, arr1 + 5, arr3, arr3 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_symmetric_difference(arr2, arr2 + 5, arr3, arr3 + 5, exp, std::less<int>());\n  mystl::set_symmetric_difference(arr2, arr2 + 5, arr3, arr3 + 5, act, std::less<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(set_union_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 1,3,5,7,9 };\n  int arr3[] = { 2,4,6,8,10 };\n  int exp[10] = { 0 }, act[10] = { 0 };\n  std::set_union(arr1, arr1 + 5, arr2, arr2 + 5, exp);\n  mystl::set_union(arr1, arr1 + 5, arr2, arr2 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_union(arr1, arr1 + 5, arr3, arr3 + 5, exp);\n  mystl::set_union(arr1, arr1 + 5, arr3, arr3 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::set_union(arr2, arr2 + 5, arr3, arr3 + 5, exp, std::less<int>());\n  mystl::set_union(arr2, arr2 + 5, arr3, arr3 + 5, act, std::less<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\n// numeric test\nTEST(accumulate_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  EXPECT_EQ(std::accumulate(arr1, arr1 + 5, 0),\n            mystl::accumulate(arr1, arr1 + 5, 0));\n  EXPECT_EQ(std::accumulate(arr1, arr1 + 5, 5),\n            mystl::accumulate(arr1, arr1 + 5, 5));\n  EXPECT_EQ(std::accumulate(arr1, arr1 + 5, 0, std::minus<int>()),\n            mystl::accumulate(arr1, arr1 + 5, 0, std::minus<int>()));\n}\n\nTEST(adjacent_difference_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 1,1,1,1,1 };\n  int exp[5], act[5];\n  std::adjacent_difference(arr1, arr1 + 5, exp);\n  mystl::adjacent_difference(arr1, arr1 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::adjacent_difference(arr2, arr2 + 5, exp, std::minus<int>());\n  mystl::adjacent_difference(arr2, arr2 + 5, act, std::minus<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(inner_product_test)\n{\n  int arr1[] = { 1,1,1,1,1 };\n  int arr2[] = { 2,2,2,2,2 };\n  int arr3[] = { 1,2,3,4,5 };\n  EXPECT_EQ(std::inner_product(arr1, arr1 + 5, arr3, 0),\n            mystl::inner_product(arr1, arr1 + 5, arr3, 0));\n  EXPECT_EQ(std::inner_product(arr2, arr2 + 5, arr3, 0, std::minus<int>(), std::multiplies<int>()),\n            mystl::inner_product(arr2, arr2 + 5, arr3, 0, std::minus<int>(), std::multiplies<int>()));\n}\n\nTEST(iota_test)\n{\n  int arr1[10];\n  int arr2[10];\n  std::iota(arr1, arr1 + 10, 1);\n  mystl::iota(arr2, arr2 + 10, 1);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::iota(arr1, arr1 + 10, -1);\n  mystl::iota(arr2, arr2 + 10, -1);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(partial_sum_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int exp1[5], act1[5];\n  int exp2[9], act2[9];\n  std::partial_sum(arr1, arr1 + 5, exp1);\n  mystl::partial_sum(arr1, arr1 + 5, act1);\n  std::partial_sum(arr1, arr1 + 9, exp2);\n  mystl::partial_sum(arr1, arr1 + 9, act2);\n  EXPECT_CON_EQ(exp1, act1);\n  EXPECT_CON_EQ(exp2, act2);\n  std::partial_sum(arr1, arr1 + 9, exp2, std::multiplies<int>());\n  mystl::partial_sum(arr1, arr1 + 9, act2, std::multiplies<int>());\n  EXPECT_CON_EQ(exp2, act2);\n}\n\n// algo test\nTEST(adjacent_find_test)\n{\n  int arr1[] = { 1,2,3,3,4 };\n  int arr2[] = { 1,2,3,4,5 };\n  EXPECT_EQ(std::adjacent_find(arr1, arr1 + 5),\n            mystl::adjacent_find(arr1, arr1 + 5));\n  EXPECT_EQ(std::adjacent_find(arr2, arr2 + 5),\n            mystl::adjacent_find(arr2, arr2 + 5));\n  EXPECT_EQ(std::adjacent_find(arr1, arr1 + 5, std::greater<int>()),\n            mystl::adjacent_find(arr1, arr1 + 5, std::greater<int>()));\n}\n\nTEST(all_of_test)\n{\n  int arr1[] = { 1,3,5,7,9 };\n  int arr2[] = { 1,3,5,7,8 };\n  EXPECT_EQ(std::all_of(arr1, arr1 + 5, is_odd),\n            mystl::all_of(arr1, arr1 + 5, is_odd));\n  EXPECT_EQ(std::all_of(arr2, arr2 + 5, is_odd),\n            mystl::all_of(arr2, arr2 + 5, is_odd));\n}\n\nTEST(any_of_test)\n{\n  int arr1[] = { 1,2,4,6,8 };\n  int arr2[] = { 2,4,6,8,10 };\n  EXPECT_EQ(std::any_of(arr1, arr1 + 5, is_odd),\n            mystl::any_of(arr1, arr1 + 5, is_odd));\n  EXPECT_EQ(std::any_of(arr2, arr2 + 5, is_odd),\n            mystl::any_of(arr2, arr2 + 5, is_odd));\n}\n\nTEST(binary_search_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  EXPECT_EQ(std::binary_search(arr1, arr1 + 5, 1),\n            mystl::binary_search(arr1, arr1 + 5, 1));\n  EXPECT_EQ(std::binary_search(arr1, arr1 + 5, 6),\n            mystl::binary_search(arr1, arr1 + 5, 6));\n}\n\nTEST(count_test)\n{\n  int arr1[] = { 1,2,2,3,3,3,4,5,8 };\n  EXPECT_EQ(std::count(arr1, arr1 + 9, 2),\n            mystl::count(arr1, arr1 + 9, 2));\n  EXPECT_EQ(std::count(arr1, arr1 + 9, 3),\n            mystl::count(arr1, arr1 + 9, 3));\n  EXPECT_EQ(std::count(arr1, arr1 + 9, 6),\n            mystl::count(arr1, arr1 + 9, 6));\n}\n\nTEST(count_if_test)\n{\n  int arr1[] = { 1,2,2,3,3,3,4,5,8 };\n  EXPECT_EQ(std::count_if(arr1, arr1 + 9, is_odd),\n            mystl::count_if(arr1, arr1 + 9, is_odd));\n  EXPECT_EQ(std::count_if(arr1, arr1 + 9, is_even),\n            mystl::count_if(arr1, arr1 + 9, is_even));\n}\n\nTEST(equal_range_test)\n{\n  int arr1[] = { 1,2,3,3,3,4,5 };\n  auto p1 = mystl::equal_range(arr1, arr1 + 7, 3);\n  auto p2 = std::equal_range(arr1, arr1 + 7, 3);\n  auto p3 = mystl::equal_range(arr1, arr1 + 7, 6, std::equal_to<int>());\n  auto p4 = std::equal_range(arr1, arr1 + 7, 6, std::equal_to<int>());\n  EXPECT_EQ(p2.first, p1.first);\n  EXPECT_EQ(p2.second, p1.second);\n  EXPECT_EQ(p4.first, p3.first);\n  EXPECT_EQ(p4.second, p3.second);\n}\n\nTEST(find_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  EXPECT_EQ(std::find(arr1, arr1 + 5, 3), mystl::find(arr1, arr1 + 5, 3));\n  EXPECT_EQ(std::find(arr1, arr1 + 5, 6), mystl::find(arr1, arr1 + 5, 6));\n}\n\nTEST(find_end_test)\n{\n  int arr1[] = { 1,2,3,2,2,3,4,5 };\n  int arr2[] = { 2,3 };\n  int arr3[] = { 4,5,6 };\n  EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr2, arr2 + 1),\n            mystl::find_end(arr1, arr1 + 8, arr2, arr2 + 1));\n  EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr3, arr3 + 2),\n            mystl::find_end(arr1, arr1 + 8, arr3, arr3 + 2));\n  EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr3, arr3 + 2),\n            mystl::find_end(arr1, arr1 + 8, arr3, arr3 + 2));\n  EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr3, arr3, std::less<int>()),\n            mystl::find_end(arr1, arr1 + 8, arr3, arr3, std::less<int>()));\n}\n\nTEST(find_first_of_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 2,3,4 };\n  int arr3[] = { 6,7,8 };\n  EXPECT_EQ(std::find_first_of(arr1, arr1 + 5, arr2, arr2 + 3),\n            mystl::find_first_of(arr1, arr1 + 5, arr2, arr2 + 3));\n  EXPECT_EQ(std::find_first_of(arr1, arr1 + 5, arr3, arr3 + 3, std::equal_to<int>()),\n            mystl::find_first_of(arr1, arr1 + 5, arr3, arr3 + 3, std::equal_to<int>()));\n}\n\nTEST(find_if_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  EXPECT_EQ(std::find_if(arr1, arr1 + 5, is_odd),\n            mystl::find_if(arr1, arr1 + 5, is_odd));\n  EXPECT_EQ(std::find_if(arr1, arr1 + 5, is_even),\n            mystl::find_if(arr1, arr1 + 5, is_even));\n}\n\nTEST(find_if_not_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  EXPECT_EQ(std::find_if_not(arr1, arr1 + 5, is_odd),\n            mystl::find_if_not(arr1, arr1 + 5, is_odd));\n  EXPECT_EQ(std::find_if_not(arr1, arr1 + 5, is_even),\n            mystl::find_if_not(arr1, arr1 + 5, is_even));\n}\n\nTEST(for_each_test)\n{\n  std::vector<int> v1{ 1,2,3,4,5 };\n  std::for_each(v1.begin(), v1.end(), arr_sum);\n  EXPECT_EQ(15, for_each_sum);\n  mystl::for_each(v1.begin(), v1.end(), arr_sum);\n  EXPECT_EQ(30, for_each_sum);\n}\n\nTEST(generate_test)\n{\n  int arr1[5];\n  int arr2[5];\n  std::generate(arr1, arr1 + 5, gen);\n  mystl::generate(arr2, arr2 + 5, gen);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(generate_n_test)\n{\n  int arr1[] = { 1,1,1,1,1,6,7,8,9,10 };\n  int arr2[] = { 2,2,2,2,2,6,7,8,9,10 };\n  std::generate_n(arr1, 5, gen);\n  mystl::generate_n(arr2, 5, gen);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(includes_test)\n{\n  std::vector<int> v1{ 1,2,3,4,5,6,7,8,9 };\n  std::vector<int> v2{ 2,3,5,6,9 };\n  std::vector<int> v3{ 0,1,2,3,4 };\n  std::vector<int> v4{ 1,2,5,7,10 };\n  std::vector<int> v5;\n  EXPECT_EQ(std::includes(v1.begin(), v1.end(), v2.begin(), v2.end()),\n            mystl::includes(v1.begin(), v1.end(), v2.begin(), v2.end()));\n  EXPECT_EQ(std::includes(v1.begin(), v1.end(), v3.begin(), v3.end()),\n            mystl::includes(v1.begin(), v1.end(), v3.begin(), v3.end()));\n  EXPECT_EQ(std::includes(v1.begin(), v1.end(), v4.begin(), v4.end()),\n            mystl::includes(v1.begin(), v1.end(), v4.begin(), v4.end()));\n  EXPECT_EQ(std::includes(v1.begin(), v1.end(), v5.begin(), v5.end(), std::less<int>()),\n            mystl::includes(v1.begin(), v1.end(), v5.begin(), v5.end(), std::less<int>()));\n}\n\nTEST(inplace_merge_test)\n{\n  int arr1[] = { 1,3,5,7,9,2,4,6,8,10 };\n  int arr2[] = { 1,3,5,7,9,2,4,6,8,10 };\n  int arr3[] = { 1,2,3,1,2,3,4,5 };\n  int arr4[] = { 1,2,3,1,2,3,4,5 };\n  std::inplace_merge(arr1, arr1 + 5, arr1 + 10);\n  mystl::inplace_merge(arr2, arr2 + 5, arr2 + 10);\n  std::inplace_merge(arr3, arr3 + 3, arr3 + 8, std::less<int>());\n  mystl::inplace_merge(arr4, arr4 + 3, arr4 + 8, std::less<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n  EXPECT_CON_EQ(arr3, arr4);\n}\n\nTEST(is_heap_test)\n{\n  int arr1[] = { 0,1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 9,8,7,6,5,4,3,2,1,0 };\n  int arr3[] = { 1,3,5,7,9,0,2,4,6,8 };\n  int arr4[] = { 0,1,2,3,4,5,6,7,8,9 };\n  std::make_heap(arr4, arr4 + 10);\n  EXPECT_EQ(std::is_heap(arr1, arr1 + 10), mystl::is_heap(arr1, arr1 + 10));\n  EXPECT_EQ(std::is_heap(arr2, arr2 + 10, std::less<int>()),\n            mystl::is_heap(arr2, arr2 + 10, std::less<int>()));\n  EXPECT_EQ(std::is_heap(arr3, arr3 + 10), mystl::is_heap(arr3, arr3 + 10));\n  EXPECT_EQ(std::is_heap(arr4, arr4 + 10), mystl::is_heap(arr4, arr4 + 10));\n}\n\nTEST(is_sorted_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 1,2,3,5,4 };\n  int arr3[] = { 5,4,3,2,1 };\n  int arr4[] = { 1,2,5,4,3 };\n  EXPECT_EQ(std::is_sorted(arr1, arr1 + 5), mystl::is_sorted(arr1, arr1 + 5));\n  EXPECT_EQ(std::is_sorted(arr2, arr2 + 5), mystl::is_sorted(arr2, arr2 + 5));\n  EXPECT_EQ(std::is_sorted(arr3, arr3 + 5, std::less<int>()),\n            mystl::is_sorted(arr3, arr3 + 5, std::less<int>()));\n  EXPECT_EQ(std::is_sorted(arr4, arr4 + 5, std::less<int>()),\n            mystl::is_sorted(arr4, arr4 + 5, std::less<int>()));\n}\n\nTEST(lower_bound_test)\n{\n  int arr1[] = { 1,2,3,3,3,4,5 };\n  EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 1),\n            mystl::lower_bound(arr1, arr1 + 7, 1));\n  EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 2),\n            mystl::lower_bound(arr1, arr1 + 7, 2));\n  EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 3),\n            mystl::lower_bound(arr1, arr1 + 7, 3));\n  EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 5, std::less<int>()),\n            mystl::lower_bound(arr1, arr1 + 7, 5, std::less<int>()));\n}\n\nTEST(max_elememt_test)\n{\n  int arr1[] = { 1,2,3,4,5,4,3,2,1 };\n  double arr2[] = { 1.0,2.2,6.6,8.8,8.81,2.4 };\n  EXPECT_PTR_EQ(std::max_element(arr1, arr1 + 9),\n                mystl::max_element(arr1, arr1 + 9));\n  EXPECT_PTR_EQ(std::max_element(arr2, arr2 + 6, std::less<double>()),\n                mystl::max_element(arr2, arr2 + 6, std::less<double>()));\n}\n\nTEST(median_test)\n{\n  int ia = 2, ib = 1, ic = 3;\n  double da = 3.1, db = 3.0, dc = 3.2;\n  EXPECT_EQ(2, mystl::median(ia, ib, ic));\n  EXPECT_EQ(3.1, mystl::median(da, db, dc, std::greater<double>()));\n}\n\nTEST(merge_test)\n{\n  int arr1[] = { 1,2,5,9,10 };\n  int arr2[] = { 3,7,8,8,9 };\n  int arr3[] = { 1,2,5,9,10 };\n  int arr4[] = { 3,7,8,8,9 };\n  int exp[10], act[10];\n  std::merge(arr1, arr1 + 5, arr2, arr2 + 5, exp);\n  mystl::merge(arr3, arr3 + 5, arr4, arr4 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::merge(arr1, arr1 + 5, arr2, arr2 + 5, exp, std::less<int>());\n  mystl::merge(arr3, arr3 + 5, arr4, arr4 + 5, act, std::less<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(min_elememt_test)\n{\n  int arr1[] = { 2,4,8,1,6,5,8,9,3 };\n  double arr2[] = { 1.5,2.2,1.4,1.33,1.333,2.33 };\n  EXPECT_PTR_EQ(std::max_element(arr1, arr1 + 9),\n                mystl::max_element(arr1, arr1 + 9));\n  EXPECT_PTR_EQ(std::max_element(arr2, arr2 + 6, std::less<double>()),\n                mystl::max_element(arr2, arr2 + 6, std::less<double>()));\n}\n\nTEST(is_permutation_test)\n{\n  int arr1[] = { 1,2,3,4,5 };\n  int arr2[] = { 3,4,5,2,1 };\n  int arr3[] = { 1,2,3,4,6 };\n  // 因为提供的是 C++11 的支持，std::is_permutation 可能没有 C++14 的接口\n  EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr2),\n            mystl::is_permutation(arr1, arr1 + 5, arr2, arr2 + 5));\n  EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr3),\n            mystl::is_permutation(arr1, arr1 + 5, arr3, arr3 + 5));\n  EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr2, std::equal_to<int>()),\n            mystl::is_permutation(arr1, arr1 + 5, arr2, arr2 + 5, std::equal_to<int>()));\n  EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr3, std::equal_to<int>()),\n            mystl::is_permutation(arr1, arr1 + 5, arr3, arr3 + 5, std::equal_to<int>()));\n}\n\nTEST(next_permutation_test)\n{\n  int arr1[] = { 1,2,3,3 };\n  int arr2[] = { 1,2,3,3 };\n  int n1 = 0, n2 = 0;\n  while (std::next_permutation(arr1, arr1 + 4))    n1++;\n  while (mystl::next_permutation(arr1, arr1 + 4))    n2++;\n  EXPECT_EQ(n1, n2);\n  for (; n1 > 0; n1--)\n  {\n    std::next_permutation(arr1, arr1 + 4);\n    mystl::next_permutation(arr2, arr2 + 4);\n    EXPECT_CON_EQ(arr1, arr2);\n  }\n  std::next_permutation(arr1, arr1 + 4, std::greater<int>());\n  mystl::next_permutation(arr2, arr2 + 4, std::greater<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(none_of_test)\n{\n  int arr1[] = { 1,3,5,7,9 };\n  int arr2[] = { 1,3,5,7,8 };\n  int arr3[] = { 2,4,6,8,10 };\n  EXPECT_EQ(std::none_of(arr1, arr1 + 5, is_even),\n            mystl::none_of(arr1, arr1 + 5, is_even));\n  EXPECT_EQ(std::none_of(arr2, arr2 + 5, is_even),\n            mystl::none_of(arr2, arr2 + 5, is_even));\n  EXPECT_EQ(std::none_of(arr3, arr3 + 5, is_even),\n            mystl::none_of(arr3, arr3 + 5, is_even));\n}\n\nTEST(nth_element_test)\n{\n  int arr1[] = { 9,8,7,6,5,4,3,2,1 };\n  int arr2[] = { 1,2,3,4,5,6,3,2,1 };\n  int arr3[] = { 1,2,8,9,6,5,3,4,7 };\n  int arr4[] = { 1,5,1,5,8,4,9,6,8,4,10,13,20,4,2,1 };\n  mystl::nth_element(arr1, arr1 + 4, arr1 + 9);\n  mystl::nth_element(arr2, arr2 + 2, arr2 + 9);\n  mystl::nth_element(arr3, arr3 + 8, arr3 + 9, std::less<int>());\n  mystl::nth_element(arr4, arr4 + 3, arr4 + 16, std::less<int>());\n  bool arr1_left_less = true, arr1_right_greater = true;\n  bool arr2_left_less = true, arr2_right_greater = true;\n  bool arr3_left_less = true, arr3_right_greater = true;\n  bool arr4_left_less = true, arr4_right_greater = true;\n  for (int i = 0; i < 9; ++i)\n  {\n    if (i < 4 && arr1[i] > arr1[4])    arr1_left_less = false;\n    else if (i > 4 && arr1[i] < arr1[4])    arr1_right_greater = false;\n  }\n  for (int i = 0; i < 9; ++i)\n  {\n    if (i < 2 && arr2[i] > arr2[2])    arr2_left_less = false;\n    else if (i > 2 && arr2[i] < arr2[2])    arr2_right_greater = false;\n  }\n  for (int i = 0; i < 9; ++i)\n  {\n    if (i < 8 && arr3[i] > arr3[8])    arr3_left_less = false;\n  }\n  for (int i = 0; i < 16; ++i)\n  {\n    if (i < 3 && arr4[i] > arr4[3])    arr4_left_less = false;\n    else if (i > 3 && arr4[i] < arr4[3])    arr4_right_greater = false;\n  }\n  EXPECT_TRUE(arr1_left_less);\n  EXPECT_TRUE(arr1_right_greater);\n  EXPECT_TRUE(arr2_left_less);\n  EXPECT_TRUE(arr2_right_greater);\n  EXPECT_TRUE(arr3_left_less);\n  EXPECT_TRUE(arr3_right_greater);\n  EXPECT_TRUE(arr4_left_less);\n  EXPECT_TRUE(arr4_right_greater);\n}\n\nTEST(partial_sort_test)\n{\n  int arr1[] = { 3,2,1,9,8,7,6,5,4 };\n  int arr2[] = { 3,2,1,9,8,7,6,5,4 };\n  int arr3[] = { 5,1,5,8,6,4,8,4,1,3,5,8,4 };\n  int arr4[] = { 5,1,5,8,6,4,8,4,1,3,5,8,4 };\n  std::partial_sort(arr1, arr1 + 2, arr1 + 9);\n  mystl::partial_sort(arr2, arr2 + 2, arr2 + 9);\n  std::partial_sort(arr3, arr3 + 5, arr3 + 13, std::greater<int>());\n  mystl::partial_sort(arr4, arr4 + 5, arr4 + 13, std::greater<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n  EXPECT_CON_EQ(arr3, arr4);\n}\n\nTEST(partial_sort_copy_test)\n{\n  int arr1[] = { 3,2,1,9,8,7,6,5,4 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr3[] = { 1,6,8,4,2,1,6,8,4,7,6,2,1,3,6 };\n  int exp[5], act[5];\n  std::partial_sort_copy(arr1, arr1 + 9, exp, exp + 5);\n  mystl::partial_sort_copy(arr1, arr1 + 9, act, act + 5);\n  EXPECT_CON_EQ(exp, act);\n  std::partial_sort_copy(arr2, arr2 + 9, exp, exp + 5);\n  mystl::partial_sort_copy(arr2, arr2 + 9, act, act + 5);\n  EXPECT_CON_EQ(exp, act);\n  std::partial_sort_copy(arr3, arr3 + 15, exp, exp + 5, std::greater<int>());\n  mystl::partial_sort_copy(arr3, arr3 + 15, act, act + 5, std::greater<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(partition_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  std::partition(arr1, arr1 + 9, is_odd);\n  mystl::partition(arr2, arr2 + 9, is_odd);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::partition(arr1, arr1 + 9, is_even);\n  mystl::partition(arr2, arr2 + 9, is_even);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(partition_copy_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };\n  int exp_true[5], exp_false[5];\n  int act_true[5], act_false[5];\n  std::partition_copy(arr1, arr1 + 10, exp_true, exp_false, is_odd);\n  mystl::partition_copy(arr1, arr1 + 10, act_true, act_false, is_odd);\n  EXPECT_CON_EQ(exp_true, act_true);\n  EXPECT_CON_EQ(exp_false, act_false);\n}\n\nTEST(prev_permutation_test)\n{\n  int arr1[] = { 3,2,1,1 };\n  int arr2[] = { 3,2,1,1 };\n  int n1 = 0, n2 = 0;\n  while (std::prev_permutation(arr1, arr1 + 4))    n1++;\n  while (mystl::prev_permutation(arr1, arr1 + 4))    n2++;\n  EXPECT_EQ(n1, n2);\n  for (; n1 > 0; n1--)\n  {\n    std::prev_permutation(arr1, arr1 + 4);\n    mystl::prev_permutation(arr2, arr2 + 4);\n    EXPECT_CON_EQ(arr1, arr2);\n  }\n  std::prev_permutation(arr1, arr1 + 4, std::greater<int>());\n  mystl::prev_permutation(arr2, arr2 + 4, std::greater<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(random_shuffle_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[9];\n  for (int i = 0; i < 9; ++i)\n  {\n    std::copy(arr1, arr1 + 9, arr2);\n    mystl::random_shuffle(arr1, arr1 + 9);\n    EXPECT_CON_NE(arr1, arr2);\n  }\n  std::copy(arr1, arr1 + 9, arr2);\n  mystl::random_shuffle(arr1, arr1 + 9, r);\n  EXPECT_CON_NE(arr1, arr2);\n}\n\nTEST(remove_test)\n{\n  std::vector<int> v1{ 1,2,3,4,5,6,6,6 };\n  std::vector<int> v2(v1);\n  std::remove(v1.begin(), v1.end(), 3);\n  mystl::remove(v2.begin(), v2.end(), 3);\n  EXPECT_CON_EQ(v1, v2);\n  std::remove(v1.begin(), v1.end(), 6);\n  mystl::remove(v2.begin(), v2.end(), 6);\n  EXPECT_CON_EQ(v1, v2);\n}\n\nTEST(remove_copy_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,6,6 };\n  int arr2[] = { 1,2,3,4,5,6,6,6 };\n  int exp[5], act[5];\n  std::remove_copy(arr1, arr1 + 8, exp, 6);\n  mystl::remove_copy(arr2, arr2 + 8, act, 6);\n  EXPECT_CON_EQ(exp, act);\n  std::remove_copy(arr1, arr1 + 5, exp, 3);\n  mystl::remove_copy(arr2, arr2 + 5, act, 3);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(remove_copy_if_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };\n  int exp[5], act[5];\n  std::remove_copy_if(arr1, arr1 + 10, exp, is_odd);\n  mystl::remove_copy_if(arr1, arr1 + 10, act, is_odd);\n  EXPECT_CON_EQ(exp, act);\n  std::remove_copy_if(arr1, arr1 + 10, exp, is_even);\n  mystl::remove_copy_if(arr1, arr1 + 10, act, is_even);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(remove_if_test)\n{\n  std::vector<int> v1{ 1,2,3,4,5,6,7,8,9,10 };\n  std::vector<int> v2(v1);\n  std::remove_if(v1.begin(), v1.end(), is_odd);\n  mystl::remove_if(v2.begin(), v2.end(), is_odd);\n  EXPECT_CON_EQ(v1, v2);\n}\n\nTEST(replace_test)\n{\n  int arr1[] = { 1,1,1,2,2,2,3,3,3 };\n  int arr2[] = { 1,1,1,2,2,2,3,3,3 };\n  std::replace(arr1, arr1 + 9, 1, 4);\n  mystl::replace(arr2, arr2 + 9, 1, 4);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::replace(arr1, arr1 + 9, 2, 5);\n  mystl::replace(arr2, arr2 + 9, 2, 5);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::replace(arr1, arr1 + 9, 3, 6);\n  mystl::replace(arr2, arr2 + 9, 3, 6);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(replace_copy_test)\n{\n  int arr1[] = { 1,1,1,2,2,2,3,3,3 };\n  int exp[9], act[9];\n  std::replace_copy(arr1, arr1 + 9, exp, 1, 4);\n  mystl::replace_copy(arr1, arr1 + 9, act, 1, 4);\n  EXPECT_CON_EQ(exp, act);\n  std::replace_copy(arr1, arr1 + 9, exp, 2, 5);\n  mystl::replace_copy(arr1, arr1 + 9, act, 2, 5);\n  EXPECT_CON_EQ(exp, act);\n  std::replace_copy(arr1, arr1 + 9, exp, 3, 6);\n  mystl::replace_copy(arr1, arr1 + 9, act, 3, 6);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(replace_copy_if_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };\n  int exp[10] = { 0 }, act[10] = { 0 };\n  std::replace_copy_if(arr1, arr1 + 10, exp, is_odd, 1);\n  mystl::replace_copy_if(arr1, arr1 + 10, act, is_odd, 1);\n  EXPECT_CON_EQ(exp, act);\n  std::replace_copy_if(arr1, arr1 + 10, exp, is_even, 2);\n  mystl::replace_copy_if(arr1, arr1 + 10, act, is_even, 2);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(replace_if_test)\n{\n  std::vector<int> v1{ 1,2,3,4,5,6,7,8,9,10 };\n  std::vector<int> v2(v1);\n  std::replace_if(v1.begin(), v1.end(), is_odd, 1);\n  mystl::replace_if(v2.begin(), v2.end(), is_odd, 1);\n  EXPECT_CON_EQ(v1, v2);\n  std::replace_if(v1.begin(), v1.end(), is_even, 2);\n  mystl::replace_if(v2.begin(), v2.end(), is_even, 2);\n  EXPECT_CON_EQ(v1, v2);\n}\n\nTEST(reverse_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  std::reverse(arr1, arr1 + 9);\n  mystl::reverse(arr2, arr2 + 9);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::reverse(arr1, arr1 + 5);\n  mystl::reverse(arr2, arr2 + 5);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(reverse_copy_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int exp[5], act[5];\n  std::reverse_copy(arr1, arr1 + 5, exp);\n  mystl::reverse_copy(arr1, arr1 + 5, act);\n  EXPECT_CON_EQ(exp, act);\n  std::reverse_copy(arr1 + 4, arr1 + 9, exp);\n  mystl::reverse_copy(arr1 + 4, arr1 + 9, act);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(rotate_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 1,2,3,4,5,6,7,8,9 };\n  std::rotate(arr1, arr1 + 3, arr1 + 9);\n  mystl::rotate(arr2, arr2 + 3, arr2 + 9);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::rotate(arr1 + 3, arr1 + 5, arr1 + 9);\n  mystl::rotate(arr2 + 3, arr2 + 5, arr2 + 9);\n  EXPECT_CON_EQ(arr1, arr2);\n  std::rotate(arr1, arr1 + 9, arr1 + 9);\n  mystl::rotate(arr2, arr2 + 9, arr2 + 9);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(rotate_copy_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int exp[9], act[9];\n  std::rotate_copy(arr1, arr1 + 5, arr1 + 9, exp);\n  mystl::rotate_copy(arr1, arr1 + 5, arr1 + 9, act);\n  EXPECT_CON_EQ(exp, act);\n  std::rotate_copy(arr1, arr1, arr1 + 9, exp);\n  mystl::rotate_copy(arr1, arr1, arr1 + 9, act);\n  EXPECT_CON_EQ(exp, act);\n  std::rotate_copy(arr1, arr1 + 9, arr1 + 9, exp);\n  mystl::rotate_copy(arr1, arr1 + 9, arr1 + 9, act);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(search_test)\n{\n  int arr1[] = { 1,2,3,3,3,4,5,6,6, };\n  int arr2[] = { 1 };\n  int arr3[] = { 3,3 };\n  int arr4[] = { 5,6,6,6 };\n  EXPECT_EQ(std::search(arr1, arr1 + 9, arr2, arr2 + 1),\n            mystl::search(arr1, arr1 + 9, arr2, arr2 + 1));\n  EXPECT_EQ(std::search(arr1, arr1 + 9, arr3, arr3 + 2),\n            mystl::search(arr1, arr1 + 9, arr3, arr3 + 2));\n  EXPECT_EQ(std::search(arr1, arr1 + 9, arr4, arr4 + 3, std::less<int>()),\n            mystl::search(arr1, arr1 + 9, arr4, arr4 + 3, std::less<int>()));\n  EXPECT_EQ(std::search(arr1, arr1 + 9, arr4, arr4 + 4, std::less<int>()),\n            mystl::search(arr1, arr1 + 9, arr4, arr4 + 4, std::less<int>()));\n}\n\nTEST(search_n_test)\n{\n  int arr1[] = { 1,2,2,3,3,3,6,6,9 };\n  EXPECT_EQ(std::search_n(arr1, arr1 + 9, 1, 0),\n            mystl::search_n(arr1, arr1 + 9, 1, 0));\n  EXPECT_EQ(std::search_n(arr1, arr1 + 9, 2, 2),\n            mystl::search_n(arr1, arr1 + 9, 2, 2));\n  EXPECT_EQ(std::search_n(arr1, arr1 + 9, 1, 3),\n            mystl::search_n(arr1, arr1 + 9, 1, 3));\n  EXPECT_EQ(std::search_n(arr1, arr1 + 9, 3, 6, std::less<int>()),\n            mystl::search_n(arr1, arr1 + 9, 3, 6, std::less<int>()));\n  EXPECT_EQ(std::search_n(arr1, arr1 + 9, 2, 10, std::less<int>()),\n            mystl::search_n(arr1, arr1 + 9, 2, 10, std::less<int>()));\n}\n\nTEST(sort_test)\n{\n  int arr1[] = { 6,1,2,5,4,8,3,2,4,6,10,2,1,9 };\n  int arr2[] = { 6,1,2,5,4,8,3,2,4,6,10,2,1,9 };\n  int arr3[] = { 80,30,51,65,12,10,24,87,62,51,32,45,1,33,66,20,35,84,62,14 };\n  int arr4[] = { 80,30,51,65,12,10,24,87,62,51,32,45,1,33,66,20,35,84,62,14 };\n  int arr5[] = { 9,9,9,8,8,8,7,7,7 };\n  int arr6[] = { 9,9,9,8,8,8,7,7,7 };\n  std::sort(arr1, arr1 + 14);\n  mystl::sort(arr2, arr2 + 14);\n  std::sort(arr3, arr3 + 20);\n  mystl::sort(arr4, arr4 + 20);\n  std::sort(arr5, arr5 + 9, std::greater<int>());\n  mystl::sort(arr6, arr6 + 9, std::greater<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n  EXPECT_CON_EQ(arr3, arr4);\n  EXPECT_CON_EQ(arr5, arr6);\n}\n\nTEST(swap_ranges_test)\n{\n  int arr1[] = { 4,5,6,1,2,3 };\n  int arr2[] = { 4,5,6,1,2,3 };\n  int arr3[] = { 1,2,3,4,5,6 };\n  int arr4[] = { 1,2,3,4,5,6 };\n  int arr5[] = { 1,1,1 };\n  int arr6[] = { 1,1,1 };\n  std::swap_ranges(arr1, arr1 + 6, arr3);\n  mystl::swap_ranges(arr2, arr2 + 6, arr4);\n  std::swap_ranges(arr1, arr1 + 3, arr5);\n  mystl::swap_ranges(arr2, arr2 + 3, arr6);\n  EXPECT_CON_EQ(arr1, arr2);\n  EXPECT_CON_EQ(arr1, arr2);\n}\n\nTEST(transform_test)\n{\n  int arr1[] = { 1,2,3,4,5,6,7,8,9 };\n  int arr2[] = { 9,8,7,6,5,4,3,2,1 };\n  int exp[9], act[9];\n  std::transform(arr1, arr1 + 9, exp, unary_op);\n  mystl::transform(arr1, arr1 + 9, act, unary_op);\n  EXPECT_CON_EQ(exp, act);\n  std::transform(arr1, arr1 + 9, arr2, exp, binary_op);\n  mystl::transform(arr1, arr1 + 9, arr2, act, binary_op);\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(unique_test)\n{\n  int arr1[] = { 1,1,1,2,2,3,4,4,5,6 };\n  int arr2[] = { 1,1,1,2,2,3,4,4,5,6 };\n  int arr3[] = { 1,2,3,6,6,6,8,8,9 };\n  int arr4[] = { 1,2,3,6,6,6,8,8,9 };\n  std::unique(arr1, arr1 + 10);\n  mystl::unique(arr2, arr2 + 10);\n  std::unique(arr3, arr3 + 9, std::equal_to<int>());\n  mystl::unique(arr4, arr4 + 9, std::equal_to<int>());\n  EXPECT_CON_EQ(arr1, arr2);\n  EXPECT_CON_EQ(arr3, arr4);\n}\n\nTEST(unique_copy_test)\n{\n  int arr1[] = { 1,1,1,2,2,3,4,4,5,6 };\n  int arr2[] = { 1,2,3,6,6,6,8,8,9 };\n  int exp[6], act[6];\n  std::unique_copy(arr1, arr1 + 10, exp);\n  mystl::unique_copy(arr1, arr1 + 10, act);\n  EXPECT_CON_EQ(exp, act);\n  std::unique_copy(arr2, arr2 + 9, exp, std::equal_to<int>());\n  mystl::unique_copy(arr2, arr2 + 9, act, std::equal_to<int>());\n  EXPECT_CON_EQ(exp, act);\n}\n\nTEST(upper_bound_test)\n{\n  int arr1[] = { 1,2,3,3,3,4,5,6,6 };\n  EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 0),\n            mystl::upper_bound(arr1, arr1 + 9, 0));\n  EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 1),\n            mystl::upper_bound(arr1, arr1 + 9, 1));\n  EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 3),\n            mystl::upper_bound(arr1, arr1 + 9, 3));\n  EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 6, std::less<int>()),\n            mystl::upper_bound(arr1, arr1 + 9, 6, std::less<int>()));\n  EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 7, std::less<int>()),\n            mystl::upper_bound(arr1, arr1 + 9, 7, std::less<int>()));\n}\n\n} // namespace algorithm_test\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif // _MSC_VER\n\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_ALGORITHM_TEST_H_\n"
  },
  {
    "path": "Test/deque_test.h",
    "content": "﻿#ifndef MYTINYSTL_DEQUE_TEST_H_\n#define MYTINYSTL_DEQUE_TEST_H_\n\n// deque test : 测试 deque 的接口和 push_front/push_back 的性能\n\n#include <deque>\n\n#include \"../MyTinySTL/deque.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace deque_test\n{\n\nvoid deque_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[----------------- Run container test : deque ------------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 1,2,3,4,5 };\n  mystl::deque<int> d1;\n  mystl::deque<int> d2(5);\n  mystl::deque<int> d3(5, 1);\n  mystl::deque<int> d4(a, a + 5);\n  mystl::deque<int> d5(d2);\n  mystl::deque<int> d6(std::move(d2));\n  mystl::deque<int> d7;\n  d7 = d3;\n  mystl::deque<int> d8;\n  d8 = std::move(d3);\n  mystl::deque<int> d9{ 1,2,3,4,5,6,7,8,9 };\n  mystl::deque<int> d10;\n  d10 = { 1,2,3,4,5,6,7,8,9 };\n\n  FUN_AFTER(d1, d1.assign(5, 1));\n  FUN_AFTER(d1, d1.assign(8, 8));\n  FUN_AFTER(d1, d1.assign(a, a + 5));\n  FUN_AFTER(d1, d1.assign({ 1,2,3,4,5 }));\n  FUN_AFTER(d1, d1.insert(d1.end(), 6));\n  FUN_AFTER(d1, d1.insert(d1.end() - 1, 2, 7));\n  FUN_AFTER(d1, d1.insert(d1.begin(), a, a + 5));\n  FUN_AFTER(d1, d1.erase(d1.begin()));\n  FUN_AFTER(d1, d1.erase(d1.begin(), d1.begin() + 4));\n  FUN_AFTER(d1, d1.emplace_back(8));\n  FUN_AFTER(d1, d1.emplace_front(8));\n  FUN_AFTER(d1, d1.emplace(d1.begin() + 1, 9));\n  FUN_AFTER(d1, d1.push_front(1));\n  FUN_AFTER(d1, d1.push_back(2));\n  FUN_AFTER(d1, d1.pop_back());\n  FUN_AFTER(d1, d1.pop_front());\n  FUN_AFTER(d1, d1.shrink_to_fit());\n  FUN_AFTER(d1, d1.resize(5));\n  FUN_AFTER(d1, d1.resize(8, 8));\n  FUN_AFTER(d1, d1.clear());\n  FUN_AFTER(d1, d1.shrink_to_fit());\n  FUN_AFTER(d1, d1.swap(d4));\n  FUN_VALUE(*(d1.begin()));\n  FUN_VALUE(*(d1.end() - 1));\n  FUN_VALUE(*(d1.rbegin()));\n  FUN_VALUE(*(d1.rend() - 1));\n  FUN_VALUE(d1.front());\n  FUN_VALUE(d1.back());\n  FUN_VALUE(d1.at(1));\n  FUN_VALUE(d1[2]);\n  std::cout << std::boolalpha;\n  FUN_VALUE(d1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(d1.size());\n  FUN_VALUE(d1.max_size());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|     push_front      |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(deque<int>, push_front, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));\n#else\n  CON_TEST_P1(deque<int>, push_front, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|     push_back       |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(deque<int>, push_back, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));\n#else\n  CON_TEST_P1(deque<int>, push_back, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[----------------- End container test : deque ------------------]\" << std::endl;\n}\n\n} // namespace deque_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_DEQUE_TEST_H_\n\n"
  },
  {
    "path": "Test/iterator_test.h",
    "content": "#ifndef MYTINYSTL_ITERATOR_TEST_H_\n#define MYTINYSTL_ITERATOR_TEST_H_\n\n#include \"test.h\"\n#include \"../MyTinySTL/iterator.h\"\n#include \"../MyTinySTL/stream_iterator.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace iterator_test\n{\n\nvoid stream_iterator_test()\n{\n  std::cout << \"[===============================================================]\\n\";\n  std::cout << \"[------------- Run iterator test : stream_iterator--------------]\\n\";\n  std::cout << \"[-------------------------- API test ---------------------------]\\n\";\n\n  static_assert(mystl::is_exactly_input_iterator<mystl::istream_iterator<int>>::value, \n                \"istream_iterator must have input_iterator_tag)\");\n\n  std::istringstream is(\"1 2 3\");  \n  mystl::istream_iterator<int> first{is}, last;   \n  std::cout << mystl::distance(first, last) << '\\n';\n\n  std::istringstream istream(\"1 2 3 4 5 6\");  \n  mystl::istream_iterator<int> beg{istream}, end;  \n  for (; beg != end; ++beg) {\n    std::cout << *beg << \" \";\n  }\n  std::cout << '\\n';\n\n  PASSED;\n}\n\n} // namespace stream_iterator_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_STREAM_ITERATOR_TEST_H_\n\n"
  },
  {
    "path": "Test/list_test.h",
    "content": "﻿#ifndef MYTINYSTL_LIST_TEST_H_\n#define MYTINYSTL_LIST_TEST_H_\n\n// list test : 测试 list 的接口与 insert, sort 的性能\n\n#include <list>\n\n#include \"../MyTinySTL/list.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace list_test\n{\n\n// 一个辅助测试函数\nbool is_odd(int x) { return x & 1; }\n\nvoid list_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[------------------ Run container test : list ------------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 1,2,3,4,5 };\n  mystl::list<int> l1;\n  mystl::list<int> l2(5);\n  mystl::list<int> l3(5, 1);\n  mystl::list<int> l4(a, a + 5);\n  mystl::list<int> l5(l2);\n  mystl::list<int> l6(std::move(l2));\n  mystl::list<int> l7{ 1,2,3,4,5,6,7,8,9 };\n  mystl::list<int> l8;\n  l8 = l3;\n  mystl::list<int> l9;\n  l9 = std::move(l3);\n  mystl::list<int> l10;\n  l10 = { 1, 2, 2, 3, 5, 6, 7, 8, 9 };\n\n  FUN_AFTER(l1, l1.assign(8, 8));\n  FUN_AFTER(l1, l1.assign(a, a + 5));\n  FUN_AFTER(l1, l1.assign({ 1,2,3,4,5,6 }));\n  FUN_AFTER(l1, l1.insert(l1.end(), 6));\n  FUN_AFTER(l1, l1.insert(l1.end(), 2, 7));\n  FUN_AFTER(l1, l1.insert(l1.begin(), a, a + 5));\n  FUN_AFTER(l1, l1.push_back(2));\n  FUN_AFTER(l1, l1.push_front(1));\n  FUN_AFTER(l1, l1.emplace(l1.begin(),1));\n  FUN_AFTER(l1, l1.emplace_front(0));\n  FUN_AFTER(l1, l1.emplace_back(10));\n  FUN_VALUE(l1.size());\n  FUN_AFTER(l1, l1.pop_front());\n  FUN_AFTER(l1, l1.pop_back());\n  FUN_AFTER(l1, l1.erase(l1.begin()));\n  FUN_AFTER(l1, l1.erase(l1.begin(), l1.end()));\n  FUN_VALUE(l1.size());\n  FUN_AFTER(l1, l1.resize(10));\n  FUN_AFTER(l1, l1.resize(5, 1));\n  FUN_AFTER(l1, l1.resize(8, 2));\n  FUN_VALUE(l1.size());\n  FUN_AFTER(l1, l1.splice(l1.end(), l4));\n  FUN_AFTER(l1, l1.splice(l1.begin(), l5, l5.begin()));\n  FUN_AFTER(l1, l1.splice(l1.end(), l6, l6.begin(), ++l6.begin()));\n  FUN_VALUE(l1.size());\n  FUN_AFTER(l1, l1.remove(0));\n  FUN_AFTER(l1, l1.remove_if(is_odd));\n  FUN_VALUE(l1.size());\n  FUN_AFTER(l1, l1.assign({ 9,5,3,3,7,1,3,2,2,0,10 }));\n  FUN_VALUE(l1.size());\n  FUN_AFTER(l1, l1.sort());\n  FUN_AFTER(l1, l1.unique());\n  FUN_AFTER(l1, l1.unique([&](int a, int b) {return b == a + 1; }));\n  FUN_AFTER(l1, l1.merge(l7));\n  FUN_AFTER(l1, l1.sort(mystl::greater<int>()));\n  FUN_AFTER(l1, l1.merge(l8, mystl::greater<int>()));\n  FUN_AFTER(l1, l1.reverse());\n  FUN_AFTER(l1, l1.clear());\n  FUN_AFTER(l1, l1.swap(l9));\n  FUN_VALUE(*l1.begin());\n  FUN_VALUE(*l1.rbegin());\n  FUN_VALUE(l1.front());\n  FUN_VALUE(l1.back());\n  std::cout << std::boolalpha;\n  FUN_VALUE(l1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(l1.size());\n  FUN_VALUE(l1.max_size());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       insert        |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P2(list<int>, insert, end, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#else\n  CON_TEST_P2(list<int>, insert, end, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|         sort        |\";\n#if LARGER_TEST_DATA_ON\n  LIST_SORT_TEST(SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#else\n  LIST_SORT_TEST(SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[------------------ End container test : list ------------------]\" << std::endl;\n}\n\n} // namespace list_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_LIST_TEST_H_\n\n"
  },
  {
    "path": "Test/map_test.h",
    "content": "﻿#ifndef MYTINYSTL_MAP_TEST_H_\n#define MYTINYSTL_MAP_TEST_H_\n\n// map test : 测试 map, multimap 的接口与它们 insert 的性能\n\n#include <map>\n\n#include \"../MyTinySTL/map.h\"\n#include \"../MyTinySTL/vector.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace map_test\n{\n\n// pair 的宏定义\n#define PAIR    mystl::pair<int, int>\n\n// map 的遍历输出\n#define MAP_COUT(m) do { \\\n    std::string m_name = #m; \\\n    std::cout << \" \" << m_name << \" :\"; \\\n    for (auto it : m)    std::cout << \" <\" << it.first << \",\" << it.second << \">\"; \\\n    std::cout << std::endl; \\\n} while(0)\n\n// map 的函数操作\n#define MAP_FUN_AFTER(con, fun) do { \\\n    std::string str = #fun; \\\n    std::cout << \" After \" << str << \" :\" << std::endl; \\\n    fun; \\\n    MAP_COUT(con); \\\n} while(0)\n\n// map 的函数值\n#define MAP_VALUE(fun) do { \\\n    std::string str = #fun; \\\n    auto it = fun; \\\n    std::cout << \" \" << str << \" : <\" << it.first << \",\" << it.second << \">\\n\"; \\\n} while(0)\n\nvoid map_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[------------------ Run container test : map -------------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  mystl::vector<PAIR> v;\n  for (int i = 0; i < 5; ++i)\n    v.push_back(PAIR(i, i));\n  mystl::map<int, int> m1;\n  mystl::map<int, int, mystl::greater<int>> m2;\n  mystl::map<int, int> m3(v.begin(), v.end());\n  mystl::map<int, int> m4(v.begin(), v.end());\n  mystl::map<int, int> m5(m3);\n  mystl::map<int, int> m6(std::move(m3));\n  mystl::map<int, int> m7;\n  m7 = m4;\n  mystl::map<int, int> m8;\n  m8 = std::move(m4);\n  mystl::map<int, int> m9{ PAIR(1,1),PAIR(3,2),PAIR(2,3) };\n  mystl::map<int, int> m10;\n  m10 = { PAIR(1,1),PAIR(3,2),PAIR(2,3) };\n\n  for (int i = 5; i > 0; --i)\n  {\n    MAP_FUN_AFTER(m1, m1.emplace(i, i));\n  }\n  MAP_FUN_AFTER(m1, m1.emplace_hint(m1.begin(), 0, 0));\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin()));\n  MAP_FUN_AFTER(m1, m1.erase(0));\n  MAP_FUN_AFTER(m1, m1.erase(1));\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.end()));\n  for (int i = 0; i < 5; ++i)\n  {\n    MAP_FUN_AFTER(m1, m1.insert(PAIR(i, i)));\n  }\n  MAP_FUN_AFTER(m1, m1.insert(v.begin(), v.end()));\n  MAP_FUN_AFTER(m1, m1.insert(m1.end(), PAIR(5, 5)));\n  FUN_VALUE(m1.count(1));\n  MAP_VALUE(*m1.find(3));\n  MAP_VALUE(*m1.lower_bound(3));\n  MAP_VALUE(*m1.upper_bound(2));\n  auto first = *m1.equal_range(2).first;\n  auto second = *m1.equal_range(2).second;\n  std::cout << \" m1.equal_range(2) : from <\" << first.first << \", \" << first.second\n    << \"> to <\" << second.first << \", \" << second.second << \">\" << std::endl;\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin()));\n  MAP_FUN_AFTER(m1, m1.erase(1));\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.find(3)));\n  MAP_FUN_AFTER(m1, m1.clear());\n  MAP_FUN_AFTER(m1, m1.swap(m9));\n  MAP_VALUE(*m1.begin());\n  MAP_VALUE(*m1.rbegin());\n  FUN_VALUE(m1[1]);\n  MAP_FUN_AFTER(m1, m1[1] = 3);\n  FUN_VALUE(m1.at(1));\n  std::cout << std::boolalpha;\n  FUN_VALUE(m1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(m1.size());\n  FUN_VALUE(m1.max_size());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  MAP_EMPLACE_TEST(map, SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#else\n  MAP_EMPLACE_TEST(map, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[------------------ End container test : map -------------------]\" << std::endl;\n}\n\nvoid multimap_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[---------------- Run container test : multimap ----------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  mystl::vector<PAIR> v;\n  for (int i = 0; i < 5; ++i)\n    v.push_back(PAIR(i, i));\n  mystl::multimap<int, int> m1;\n  mystl::multimap<int, int, mystl::greater<int>> m2;\n  mystl::multimap<int, int> m3(v.begin(), v.end());\n  mystl::multimap<int, int> m4(v.begin(), v.end());\n  mystl::multimap<int, int> m5(m3);\n  mystl::multimap<int, int> m6(std::move(m3));\n  mystl::multimap<int, int> m7;\n  m7 = m4;\n  mystl::multimap<int, int> m8;\n  m8 = std::move(m4);\n  mystl::multimap<int, int> m9{ PAIR(1,1),PAIR(3,2),PAIR(2,3) };\n  mystl::multimap<int, int> m10;\n  m10 = { PAIR(1,1),PAIR(3,2),PAIR(2,3) };\n\n  for (int i = 5; i > 0; --i)\n  {\n    MAP_FUN_AFTER(m1, m1.emplace(i, i));\n  }\n  MAP_FUN_AFTER(m1, m1.emplace_hint(m1.begin(), 0, 0));\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin()));\n  MAP_FUN_AFTER(m1, m1.erase(0));\n  MAP_FUN_AFTER(m1, m1.erase(1));\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.end()));\n  for (int i = 0; i < 5; ++i)\n  {\n    MAP_FUN_AFTER(m1, m1.insert(mystl::make_pair(i, i)));\n  }\n  MAP_FUN_AFTER(m1, m1.insert(v.begin(), v.end()));\n  MAP_FUN_AFTER(m1, m1.insert(PAIR(5, 5)));\n  MAP_FUN_AFTER(m1, m1.insert(m1.end(), PAIR(5, 5)));\n  FUN_VALUE(m1.count(3));\n  MAP_VALUE(*m1.find(3));\n  MAP_VALUE(*m1.lower_bound(3));\n  MAP_VALUE(*m1.upper_bound(2));\n  auto first = *m1.equal_range(2).first;\n  auto second = *m1.equal_range(2).second;\n  std::cout << \" m1.equal_range(2) : from <\" << first.first << \", \" << first.second\n    << \"> to <\" << second.first << \", \" << second.second << \">\" << std::endl;\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin()));\n  MAP_FUN_AFTER(m1, m1.erase(1));\n  MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.find(3)));\n  MAP_FUN_AFTER(m1, m1.clear());\n  MAP_FUN_AFTER(m1, m1.swap(m9));\n  MAP_FUN_AFTER(m1, m1.insert(PAIR(3, 3)));\n  MAP_VALUE(*m1.begin());\n  MAP_VALUE(*m1.rbegin());\n  std::cout << std::boolalpha;\n  FUN_VALUE(m1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(m1.size());\n  FUN_VALUE(m1.max_size());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  MAP_EMPLACE_TEST(multimap, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#else\n  MAP_EMPLACE_TEST(multimap, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[---------------- End container test : multimap ----------------]\" << std::endl;\n}\n\n} // namespace map_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_MAP_TEST_H_\n\n"
  },
  {
    "path": "Test/queue_test.h",
    "content": "﻿#ifndef MYTINYSTL_QUEUE_TEST_H_\n#define MYTINYSTL_QUEUE_TEST_H_\n\n// queue test : 测试 queue, priority_queue 的接口和它们 push 的性能\n\n#include <queue>\n\n#include \"../MyTinySTL/queue.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace queue_test\n{\n\nvoid queue_print(mystl::queue<int> q)\n{\n  while (!q.empty())\n  {\n    std::cout << \" \" << q.front();\n    q.pop();\n  }\n  std::cout << std::endl;\n}\n\nvoid p_queue_print(mystl::priority_queue<int> p)\n{\n  while (!p.empty())\n  {\n    std::cout << \" \" << p.top();\n    p.pop();\n  }\n  std::cout << std::endl;\n}\n\n//  queue 的遍历输出\n#define QUEUE_COUT(q) do {                       \\\n    std::string q_name = #q;                     \\\n    std::cout << \" \" << q_name << \" :\";          \\\n    queue_print(q);                              \\\n} while(0)\n\n// priority_queue 的遍历输出\n#define P_QUEUE_COUT(p) do {                     \\\n    std::string p_name = #p;                     \\\n    std::cout << \" \" << p_name << \" :\";          \\\n    p_queue_print(p);                            \\\n} while(0)\n\n#define QUEUE_FUN_AFTER(con, fun) do {           \\\n  std::string fun_name = #fun;                   \\\n  std::cout << \" After \" << fun_name << \" :\\n\";  \\\n  fun;                                           \\\n  QUEUE_COUT(con);                               \\\n} while(0)\n\n#define P_QUEUE_FUN_AFTER(con, fun) do {         \\\n  std::string fun_name = #fun;                   \\\n  std::cout << \" After \" << fun_name << \" :\\n\";  \\\n  fun;                                           \\\n  P_QUEUE_COUT(con);                             \\\n} while(0)\n\nvoid queue_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[----------------- Run container test : queue ------------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 1,2,3,4,5 };\n  mystl::deque<int> d1(5);\n  mystl::queue<int> q1;\n  mystl::queue<int> q2(5);\n  mystl::queue<int> q3(5, 1);\n  mystl::queue<int> q4(a, a + 5);\n  mystl::queue<int> q5(d1);\n  mystl::queue<int> q6(std::move(d1));\n  mystl::queue<int> q7(q2);\n  mystl::queue<int> q8(std::move(q2));\n  mystl::queue<int> q9;\n  q9 = q3;\n  mystl::queue<int> q10;\n  q10 = std::move(q3);\n  mystl::queue<int> q11{ 1,2,3,4,5 };\n  mystl::queue<int> q12;\n  q12 = { 1,2,3,4,5 };\n\n  QUEUE_FUN_AFTER(q1, q1.push(1));\n  QUEUE_FUN_AFTER(q1, q1.push(2));\n  QUEUE_FUN_AFTER(q1, q1.push(3));\n  QUEUE_FUN_AFTER(q1, q1.pop());\n  QUEUE_FUN_AFTER(q1, q1.emplace(4));\n  QUEUE_FUN_AFTER(q1, q1.emplace(5));\n  std::cout << std::boolalpha;\n  FUN_VALUE(q1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(q1.size());\n  FUN_VALUE(q1.front());\n  FUN_VALUE(q1.back());\n  while (!q1.empty())\n  {\n    QUEUE_FUN_AFTER(q1, q1.pop());\n  }\n  QUEUE_FUN_AFTER(q1, q1.swap(q4));\n  QUEUE_FUN_AFTER(q1, q1.clear());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|         push        |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(queue<int>, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));\n#else\n  CON_TEST_P1(queue<int>, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[----------------- End container test : queue ------------------]\" << std::endl;\n}\n\nvoid priority_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[------------- Run container test : priority_queue -------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 1,2,3,4,5 };\n  mystl::vector<int> v1(5);\n  mystl::priority_queue<int> p1;\n  mystl::priority_queue<int> p2(5);\n  mystl::priority_queue<int> p3(5, 1);\n  mystl::priority_queue<int> p4(a, a + 5);\n  mystl::priority_queue<int> p5(v1);\n  mystl::priority_queue<int> p6(std::move(v1));\n  mystl::priority_queue<int> p7(p2);\n  mystl::priority_queue<int> p8(std::move(p2));\n  mystl::priority_queue<int> p9;\n  p9 = p3;\n  mystl::priority_queue<int> p10;\n  p10 = std::move(p3);\n  mystl::priority_queue<int> p11{ 1,2,3,4,5 };\n  mystl::priority_queue<int> p12;\n  p12 = { 1,2,3,4,5 };\n\n  P_QUEUE_FUN_AFTER(p1, p1.push(1));\n  P_QUEUE_FUN_AFTER(p1, p1.push(5));\n  P_QUEUE_FUN_AFTER(p1, p1.push(3));\n  P_QUEUE_FUN_AFTER(p1, p1.pop());\n  P_QUEUE_FUN_AFTER(p1, p1.emplace(7));\n  P_QUEUE_FUN_AFTER(p1, p1.emplace(2));\n  P_QUEUE_FUN_AFTER(p1, p1.emplace(8));\n  std::cout << std::boolalpha;\n  FUN_VALUE(p1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(p1.size());\n  FUN_VALUE(p1.top());\n  while (!p1.empty())\n  {\n    P_QUEUE_FUN_AFTER(p1, p1.pop());\n  }\n  P_QUEUE_FUN_AFTER(p1, p1.swap(p4));\n  P_QUEUE_FUN_AFTER(p1, p1.clear());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|         push        |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(priority_queue<int>, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));\n#else\n  CON_TEST_P1(priority_queue<int>, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[------------- End container test : priority_queue -------------]\" << std::endl;\n}\n\n} // namespace queue_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_QUEUE_TEST_H_\n\n"
  },
  {
    "path": "Test/set_test.h",
    "content": "﻿#ifndef MYTINYSTL_SET_TEST_H_\n#define MYTINYSTL_SET_TEST_H_\n\n// set test : 测试 set, multiset 的接口与它们 insert 的性能\n\n#include <set>\n\n#include \"../MyTinySTL/set.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace set_test\n{\n\nvoid set_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[------------------ Run container test : set -------------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 5,4,3,2,1 };\n  mystl::set<int> s1;\n  mystl::set<int, mystl::greater<int>> s2;\n  mystl::set<int> s3(a, a + 5);\n  mystl::set<int> s4(a, a + 5);\n  mystl::set<int> s5(s3);\n  mystl::set<int> s6(std::move(s3));\n  mystl::set<int> s7;\n  s7 = s4;\n  mystl::set<int> s8;\n  s8 = std::move(s4);\n  mystl::set<int> s9{ 1,2,3,4,5 };\n  mystl::set<int> s10;\n  s10 = { 1,2,3,4,5 };\n\n  for (int i = 5; i > 0; --i)\n  {\n    FUN_AFTER(s1, s1.emplace(i));\n  }\n  FUN_AFTER(s1, s1.emplace_hint(s1.begin(), 0));\n  FUN_AFTER(s1, s1.erase(s1.begin()));\n  FUN_AFTER(s1, s1.erase(0));\n  FUN_AFTER(s1, s1.erase(1));\n  FUN_AFTER(s1, s1.erase(s1.begin(), s1.end()));\n  for (int i = 0; i < 5; ++i)\n  {\n    FUN_AFTER(s1, s1.insert(i));\n  }\n  FUN_AFTER(s1, s1.insert(a, a + 5));\n  FUN_AFTER(s1, s1.insert(5));\n  FUN_AFTER(s1, s1.insert(s1.end(), 5));\n  FUN_VALUE(s1.count(5));\n  FUN_VALUE(*s1.find(3));\n  FUN_VALUE(*s1.lower_bound(3));\n  FUN_VALUE(*s1.upper_bound(3));\n  auto first = *s1.equal_range(3).first;\n  auto second = *s1.equal_range(3).second;\n  std::cout << \" s1.equal_range(3) : from \" << first << \" to \" << second << std::endl;\n  FUN_AFTER(s1, s1.erase(s1.begin()));\n  FUN_AFTER(s1, s1.erase(1));\n  FUN_AFTER(s1, s1.erase(s1.begin(), s1.find(3)));\n  FUN_AFTER(s1, s1.clear());\n  FUN_AFTER(s1, s1.swap(s5));\n  FUN_VALUE(*s1.begin());\n  FUN_VALUE(*s1.rbegin());\n  std::cout << std::boolalpha;\n  FUN_VALUE(s1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(s1.size());\n  FUN_VALUE(s1.max_size());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(set<int>, emplace, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#else\n  CON_TEST_P1(set<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[------------------ End container test : set -------------------]\" << std::endl;\n}\n\nvoid multiset_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[---------------- Run container test : multiset ----------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 5,4,3,2,1 };\n  mystl::multiset<int> s1;\n  mystl::multiset<int, mystl::greater<int>> s2;\n  mystl::multiset<int> s3(a, a + 5);\n  mystl::multiset<int> s4(a, a + 5);\n  mystl::multiset<int> s5(s3);\n  mystl::multiset<int> s6(std::move(s3));\n  mystl::multiset<int> s7;\n  s7 = s4;\n  mystl::multiset<int> s8;\n  s8 = std::move(s4);\n  mystl::multiset<int> s9{ 1,2,3,4,5 };\n  mystl::multiset<int> s10;\n  s10 = { 1,2,3,4,5 };\n\n  for (int i = 5; i > 0; --i)\n  {\n    FUN_AFTER(s1, s1.emplace(i));\n  }\n  FUN_AFTER(s1, s1.emplace_hint(s1.begin(), 0));\n  FUN_AFTER(s1, s1.erase(s1.begin()));\n  FUN_AFTER(s1, s1.erase(0));\n  FUN_AFTER(s1, s1.erase(1));\n  FUN_AFTER(s1, s1.erase(s1.begin(), s1.end()));\n  for (int i = 0; i < 5; ++i)\n  {\n    FUN_AFTER(s1, s1.insert(i));\n  }\n  FUN_AFTER(s1, s1.insert(a, a + 5));\n  FUN_AFTER(s1, s1.insert(5));\n  FUN_AFTER(s1, s1.insert(s1.end(), 5));\n  FUN_VALUE(s1.count(5));\n  FUN_VALUE(*s1.find(3));\n  FUN_VALUE(*s1.lower_bound(3));\n  FUN_VALUE(*s1.upper_bound(3));\n  auto first = *s1.equal_range(3).first;\n  auto second = *s1.equal_range(3).second;\n  std::cout << \" s1.equal_range(3) : from \" << first << \" to \" << second << std::endl;\n  FUN_AFTER(s1, s1.erase(s1.begin()));\n  FUN_AFTER(s1, s1.erase(1));\n  FUN_AFTER(s1, s1.erase(s1.begin(), s1.find(3)));\n  FUN_AFTER(s1, s1.clear());\n  FUN_AFTER(s1, s1.swap(s5));\n  FUN_VALUE(*s1.begin());\n  FUN_VALUE(*s1.rbegin());\n  std::cout << std::boolalpha;\n  FUN_VALUE(s1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(s1.size());\n  FUN_VALUE(s1.max_size());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(multiset<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#else\n  CON_TEST_P1(multiset<int>, emplace, rand(), SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[---------------- End container test : multiset ----------------]\" << std::endl;\n}\n\n} // namespace set_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_SET_TEST_H_\n\n"
  },
  {
    "path": "Test/stack_test.h",
    "content": "﻿#ifndef MYTINYSTL_STACK_TEST_H_\n#define MYTINYSTL_STACK_TEST_H_\n\n// stack test : 测试 stack 的接口 和 push 的性能\n\n#include <stack>\n\n#include \"../MyTinySTL/stack.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace stack_test\n{\n\nvoid stack_print(mystl::stack<int> s)\n{\n  while (!s.empty())\n  {\n    std::cout << \" \" << s.top();\n    s.pop();\n  }\n  std::cout << std::endl;\n}\n\n// stack 的遍历输出\n#define STACK_COUT(s) do {                       \\\n    std::string s_name = #s;                     \\\n    std::cout << \" \" << s_name << \" :\";          \\\n    stack_print(s);                              \\\n} while(0)\n\n#define STACK_FUN_AFTER(con, fun) do {           \\\n  std::string fun_name = #fun;                   \\\n  std::cout << \" After \" << fun_name << \" :\\n\";  \\\n  fun;                                           \\\n  STACK_COUT(con);                               \\\n} while(0)\n\nvoid stack_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[----------------- Run container test : stack ------------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 1,2,3,4,5 };\n  mystl::deque<int> d1(5);\n  mystl::stack<int> s1;\n  mystl::stack<int> s2(5);\n  mystl::stack<int> s3(5, 1);\n  mystl::stack<int> s4(a, a + 5);\n  mystl::stack<int> s5(d1);\n  mystl::stack<int> s6(std::move(d1));\n  mystl::stack<int> s7(s2);\n  mystl::stack<int> s8(std::move(s2));\n  mystl::stack<int> s9;\n  s9 = s3;\n  mystl::stack<int> s10;\n  s10 = std::move(s3);\n  mystl::stack<int> s11{ 1,2,3,4,5 };\n  mystl::stack<int> s12;\n  s12 = { 1,2,3,4,5 };\n\n  STACK_FUN_AFTER(s1, s1.push(1));\n  STACK_FUN_AFTER(s1, s1.push(2));\n  STACK_FUN_AFTER(s1, s1.push(3));\n  STACK_FUN_AFTER(s1, s1.pop());\n  STACK_FUN_AFTER(s1, s1.emplace(4));\n  STACK_FUN_AFTER(s1, s1.emplace(5));\n  std::cout << std::boolalpha;\n  FUN_VALUE(s1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(s1.size());\n  FUN_VALUE(s1.top());\n  while (!s1.empty())\n  {\n    STACK_FUN_AFTER(s1, s1.pop());\n  }\n  STACK_FUN_AFTER(s1, s1.swap(s4));\n  STACK_FUN_AFTER(s1, s1.clear());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|         push        |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(stack<int>, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));\n#else\n  CON_TEST_P1(stack<int>, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[----------------- End container test : stack ------------------]\" << std::endl;\n}\n\n} // namespace stack_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_STACK_TEST_H_\n\n"
  },
  {
    "path": "Test/string_test.h",
    "content": "﻿#ifndef MYTINYSTL_STRING_TEST_H_\n#define MYTINYSTL_STRING_TEST_H_\n\n// string test : 测试 string 的接口和 insert 的性能\n\n#include <string>\n\n#include \"../MyTinySTL/astring.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace string_test\n{\n\nvoid string_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[----------------- Run container test : string -----------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  const char* s = \"abcdefg\";\n  mystl::string str;\n  mystl::string str1(5, 'a');\n  mystl::string str2(str1, 3);\n  mystl::string str3(str1, 0, 3);\n  mystl::string str4(\"abc\");\n  mystl::string str5(\"abcde\",3);\n  mystl::string str6(s, s + 5);\n  mystl::string str7(str1);\n  mystl::string str8(std::move(str1));\n  mystl::string str9;\n  str9 = str2;\n  mystl::string str10;\n  str10 = std::move(str2);\n  mystl::string str11;\n  str11 = \"123\";\n  mystl::string str12;\n  str12 = 'A';\n\n  STR_FUN_AFTER(str, str = 'a');\n  STR_FUN_AFTER(str, str = \"string\");\n  FUN_VALUE(*str.begin());\n  FUN_VALUE(*str.rbegin());\n  FUN_VALUE(*(str.end() - 1));\n  FUN_VALUE(*(str.rend() - 1));\n  FUN_VALUE(str.front());\n  FUN_VALUE(str.back());\n  FUN_VALUE(str[1]);\n  FUN_VALUE(str.at(2));\n  STR_COUT(str.data());\n  STR_COUT(str.c_str());\n  std::cout << std::boolalpha;\n  FUN_VALUE(str.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(str.size());\n  FUN_VALUE(str.length());\n  FUN_VALUE(str.capacity());\n  FUN_VALUE(str.max_size());\n  STR_FUN_AFTER(str, str.shrink_to_fit());\n  FUN_VALUE(str.capacity());\n\n  STR_FUN_AFTER(str, str.insert(str.begin(), 'a'));\n  STR_FUN_AFTER(str, str.insert(str.end(), 3, 'x'));\n  STR_FUN_AFTER(str, str.insert(str.end(), s, s + 3));\n  STR_FUN_AFTER(str, str.erase(str.begin()));\n  STR_FUN_AFTER(str, str.erase(str.begin(), str.begin() + 3));\n  STR_FUN_AFTER(str, str.clear());\n  STR_FUN_AFTER(str, str.push_back('s'));\n  STR_FUN_AFTER(str, str.push_back('t'));\n  STR_FUN_AFTER(str, str.pop_back());\n  STR_FUN_AFTER(str, str.append(1, 't'));\n  STR_FUN_AFTER(str, str.append(str4));\n  STR_FUN_AFTER(str, str.append(str4, 1));\n  STR_FUN_AFTER(str, str.append(str4, 2, 1));\n  STR_FUN_AFTER(str, str.append(\"str\"));\n  STR_FUN_AFTER(str, str.append(\"inging\", 3));\n  STR_FUN_AFTER(str, str.append(s, s + 3));\n  STR_FUN_AFTER(str, str.resize(10));\n  FUN_VALUE(str.size());\n  STR_FUN_AFTER(str, str.resize(20, 'x'));\n  FUN_VALUE(str.size());\n  STR_FUN_AFTER(str, str.clear());\n\n  STR_FUN_AFTER(str, str = \"string\");\n  STR_FUN_AFTER(str3, str3 = \"astrings\");\n  FUN_VALUE(str.compare(str3));\n  FUN_VALUE(str.compare(0, 6, str3));\n  FUN_VALUE(str.compare(0, 6, str3, 1, 6));\n  FUN_VALUE(str.compare(\"atringgg\"));\n  FUN_VALUE(str.compare(\"zzz\"));\n  FUN_VALUE(str.compare(0, 3, \"str\"));\n  FUN_VALUE(str.compare(0, 3, \"stri\", 4));\n  FUN_VALUE(str.compare(0, 3, \"s\", 2));\n  FUN_VALUE(str.compare(0, 9, \"stringabc\", 9));\n  FUN_VALUE(str.substr(0));\n  FUN_VALUE(str.substr(3));\n  FUN_VALUE(str.substr(0, 3));\n  FUN_VALUE(str.substr(0, 10));\n  STR_FUN_AFTER(str, str.replace(0, 6, str3));\n  STR_FUN_AFTER(str, str.replace(str.end() - 1, str.end(), str3));\n  STR_FUN_AFTER(str, str.replace(0, 1, \"my \"));\n  STR_FUN_AFTER(str, str.replace(str.end() - 8, str.end(), \" test\"));\n  STR_FUN_AFTER(str, str.replace(10, 4, \"replace\"));\n  STR_FUN_AFTER(str, str.replace(str.end(), str.end(), \" test\"));\n  STR_FUN_AFTER(str, str.replace(0, 2, 3, '6'));\n  STR_FUN_AFTER(str, str.replace(str.begin(), str.begin() + 3, 6, '6'));\n  STR_FUN_AFTER(str, str.replace(0, 3, str3, 1, 3));\n  STR_FUN_AFTER(str, str.replace(str.begin(), str.begin() + 6, s, s + 3));\n  STR_FUN_AFTER(str, str.reverse());\n  STR_FUN_AFTER(str, str.reverse());\n\n  STR_FUN_AFTER(str, str = \"abcabc stringgg\");\n  STR_FUN_AFTER(str3, str3 = \"abc\");\n  FUN_VALUE(str.find('a'));\n  FUN_VALUE(str.find('a', 3));\n  FUN_VALUE(str.find('a', 4));\n  FUN_VALUE(str.find(\"abc\"));\n  FUN_VALUE(str.find(\"abc\", 1));\n  FUN_VALUE(str.find(\"abc\", 1, 1));\n  FUN_VALUE(str.find(str3));\n  FUN_VALUE(str.find(str3, 1));\n  FUN_VALUE(str.rfind('g'));\n  FUN_VALUE(str.rfind('g', 3));\n  FUN_VALUE(str.rfind(\"gg\"));\n  FUN_VALUE(str.rfind(\"bc\", 10));\n  FUN_VALUE(str.rfind(str3));\n  FUN_VALUE(str.rfind(str3, 3));\n  FUN_VALUE(str.find_first_of('g'));\n  FUN_VALUE(str.find_first_of('k'));\n  FUN_VALUE(str.find_first_of(\"bca\"));\n  FUN_VALUE(str.find_first_of(\"defg\", 10));\n  FUN_VALUE(str.find_first_of(\"gnirts\"));\n  FUN_VALUE(str.find_first_of(\"abc\", 6));\n  FUN_VALUE(str.find_first_of(\"abcdf\", 2, 3));\n  FUN_VALUE(str.find_first_of(str3, 1));\n  FUN_VALUE(str.find_first_of(str3, 10));\n  FUN_VALUE(str.find_first_not_of('a'));\n  FUN_VALUE(str.find_first_not_of('d'));\n  FUN_VALUE(str.find_first_not_of('g', 14));\n  FUN_VALUE(str.find_first_not_of(\"abc\"));\n  FUN_VALUE(str.find_first_not_of(\"ggggg\", 14, 4));\n  FUN_VALUE(str.find_first_not_of(str3));\n  FUN_VALUE(str.find_first_not_of(str3, 3));\n  FUN_VALUE(str.find_last_of('a'));\n  FUN_VALUE(str.find_last_of('a', 4));\n  FUN_VALUE(str.find_last_of('g'));\n  FUN_VALUE(str.find_last_of(\"gg\"));\n  FUN_VALUE(str.find_last_of(\"gg\", 14));\n  FUN_VALUE(str.find_last_of(\"ggg\", 14, 1));\n  FUN_VALUE(str.find_last_of(str3));\n  FUN_VALUE(str.find_last_of(str3, 3));\n  FUN_VALUE(str.find_last_not_of('g'));\n  FUN_VALUE(str.find_last_not_of('a'));\n  FUN_VALUE(str.find_last_not_of('a', 1));\n  FUN_VALUE(str.find_last_not_of(\"ggg\"));\n  FUN_VALUE(str.find_last_not_of(\"ggg\", 14));\n  FUN_VALUE(str.find_last_not_of(\"abc\", 3, 1));\n  FUN_VALUE(str.find_last_not_of(str3));\n  FUN_VALUE(str.find_last_not_of(str3, 2));\n  FUN_VALUE(str.count('a'));\n  FUN_VALUE(str.count('a', 2));\n  FUN_VALUE(str.count('d', 10));\n\n  STR_FUN_AFTER(str, str.swap(str3));\n  FUN_VALUE(str.size());\n  FUN_VALUE(str.length());\n  FUN_VALUE(str.capacity());\n  STR_FUN_AFTER(str, str += str);\n  STR_FUN_AFTER(str, str += 'a');\n  STR_FUN_AFTER(str, str += \"bc\");\n  FUN_VALUE(str.size());\n  FUN_VALUE(str.length());\n  FUN_VALUE(str.capacity());\n  STR_FUN_AFTER(str, str.shrink_to_fit());\n  FUN_VALUE(str.capacity());\n  STR_FUN_AFTER(str, str.reserve(50));\n  FUN_VALUE(str.capacity());\n  STR_FUN_AFTER(str3, str3 = \"test\");\n  STR_FUN_AFTER(str4, str4 = \" ok!\");\n  std::cout << \" str3 + '!' : \" << str3 + '!' << std::endl;\n  std::cout << \" '#' + str3 : \" << '#' + str3 << std::endl;\n  std::cout << \" str3 + \\\" success\\\" : \" << str3 + \" success\" << std::endl;\n  std::cout << \" \\\"My \\\" + str3 : \" << \"My \" + str3 << std::endl;\n  std::cout << \" str3 + str4 : \" << str3 + str4 << std::endl;\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|        append       |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(string, append, \"s\", SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));\n#else\n  CON_TEST_P1(string, append, \"s\", SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[----------------- End container test : string -----------------]\" << std::endl;\n}\n\n} // namespace string_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_STRING_TEST_H_\n"
  },
  {
    "path": "Test/test.cpp",
    "content": "﻿#ifdef _MSC_VER\n#define _SCL_SECURE_NO_WARNINGS\n#endif\n\n#if defined(_MSC_VER) && defined(_DEBUG)\n#define _CRTDBG_MAP_ALLOC \n#include <stdlib.h>\n#include <crtdbg.h>\n#endif // check memory leaks\n\n#include \"algorithm_performance_test.h\"\n#include \"algorithm_test.h\"\n#include \"vector_test.h\"\n#include \"list_test.h\"\n#include \"deque_test.h\"\n#include \"queue_test.h\"\n#include \"stack_test.h\"\n#include \"map_test.h\"\n#include \"set_test.h\"\n#include \"unordered_map_test.h\"\n#include \"unordered_set_test.h\"\n#include \"string_test.h\"\n#include \"iterator_test.h\"\n\nint main()\n{\n  using namespace mystl::test;\n\n  std::cout.sync_with_stdio(false);\n\n  RUN_ALL_TESTS();\n  algorithm_performance_test::algorithm_performance_test();\n  iterator_test::stream_iterator_test();\n  vector_test::vector_test();\n  list_test::list_test();\n  deque_test::deque_test();\n  queue_test::queue_test();\n  queue_test::priority_test();\n  stack_test::stack_test();\n  map_test::map_test();\n  map_test::multimap_test();\n  set_test::set_test();\n  set_test::multiset_test();\n  unordered_map_test::unordered_map_test();\n  unordered_map_test::unordered_multimap_test();\n  unordered_set_test::unordered_set_test();\n  unordered_set_test::unordered_multiset_test();\n  string_test::string_test();\n\n#if defined(_MSC_VER) && defined(_DEBUG)\n  _CrtDumpMemoryLeaks();\n#endif // check memory leaks\n\n}\n"
  },
  {
    "path": "Test/test.h",
    "content": "﻿#ifndef MYTINYSTL_TEST_H_\n#define MYTINYSTL_TEST_H_\n\n// 一个简单的单元测试框架，定义了两个类 TestCase 和 UnitTest，以及一系列用于测试的宏\n\n#include <ctime>\n#include <cstring>\n#include <cstdio>\n#include <iostream>\n#include <iomanip>\n#include <string>\n#include <sstream>\n#include <vector>\n\n#include \"Lib/redbud/io/color.h\"\n\nnamespace mystl\n{\nnamespace test\n{\n\n#define green redbud::io::state::manual << redbud::io::hfg::green\n#define red   redbud::io::state::manual << redbud::io::hfg::red\n\n#if defined(_MSC_VER)\n#pragma warning(disable : 4244)\n#pragma warning(disable : 4996)\n#endif\n\n} // namespace test\n\nnamespace test\n{\n\n// TestCase 类\n// 封装单个测试案例\nclass TestCase\n{\npublic:\n  // 构造函数，接受一个字符串代表案例名称\n  TestCase(const char* case_name) : testcase_name(case_name) {}\n\n  // 一个纯虚函数，用于测试案例\n  virtual void Run() = 0;\n\npublic:\n  const char* testcase_name;  // 测试案例的名称\n  int         nTestResult;    // 测试案例的执行结果 \n  double      nFailed;        // 测试失败的案例数\n  double      nPassed;        // 测试通过的案例数\n};\n\n// UnitTest 类\n// 单元测试，把所有测试案例加入到 vector 中，依次执行测试案例\nclass UnitTest\n{\npublic:\n  // 获取一个案例\n  static UnitTest* GetInstance();\n\n  // 将案例依次加入 vector\n  TestCase* RegisterTestCase(TestCase* testcase);\n\n  void Run();\n\npublic:\n  TestCase* CurrentTestCase;          // 当前执行的测试案例\n  double    nPassed;                  // 通过案例数\n  double    nFailed;                  // 失败案例数\n\nprotected:\n  std::vector<TestCase*> testcases_;  // 保存案例集合\n};\n\nUnitTest* UnitTest::GetInstance()\n{\n  static UnitTest instance;\n  return &instance;\n}\n\nTestCase* UnitTest::RegisterTestCase(TestCase* testcase)\n{\n  testcases_.push_back(testcase);\n  return testcase;\n}\n\nvoid UnitTest::Run()\n{\n  for (auto it : testcases_)\n  {\n    TestCase* testcase = it;\n    CurrentTestCase = testcase;\n    testcase->nTestResult = 1;\n    testcase->nFailed = 0;\n    testcase->nPassed = 0;\n    std::cout << green << \"============================================\\n\";\n    std::cout << green << \" Run TestCase:\" << testcase->testcase_name << \"\\n\";\n    testcase->Run();\n    if (testcase->nFailed == 0)\n      std::cout << green;\n    else\n      std::cout << red;\n    std::cout << \" \" << testcase->nPassed << \" / \" << testcase->nFailed + testcase->nPassed\n      << \" Cases passed. ( \" << testcase->nPassed / \n      (testcase->nFailed + testcase->nPassed) * 100 << \"% )\\n\";\n    std::cout << green << \" End TestCase:\" << testcase->testcase_name << \"\\n\";\n    if (testcase->nTestResult)\n      ++nPassed;\n    else\n      ++nFailed;\n  }\n  std::cout << green << \"============================================\\n\";\n  std::cout << green << \" Total TestCase : \" << nPassed + nFailed << \"\\n\";\n  std::cout << green << \" Total Passed : \" << nPassed << \"\\n\";\n  std::cout << red << \" Total Failed : \" << nFailed << \"\\n\";\n  std::cout << green << \" \" << nPassed << \" / \" << nFailed + nPassed\n    << \" TestCases passed. ( \" << nPassed / (nFailed + nPassed) * 100 << \"% )\\n\";\n}\n\n/*****************************************************************************************/\n\n// 测试案例的类名，替换为 test_cast_TEST\n#define TESTCASE_NAME(testcase_name) \\\n    testcase_name##_TEST\n\n// 使用宏定义掩盖复杂的测试样例封装过程，把 TEXT 中的测试案例放到单元测试中\n#define MYTINYSTL_TEST_(testcase_name)                        \\\nclass TESTCASE_NAME(testcase_name) : public TestCase {        \\\npublic:                                                       \\\n    TESTCASE_NAME(testcase_name)(const char* case_name)       \\\n        : TestCase(case_name) {};                             \\\n    virtual void Run();                                       \\\nprivate:                                                      \\\n    static TestCase* const testcase_;                         \\\n};                                                            \\\n                                                              \\\nTestCase* const TESTCASE_NAME(testcase_name)                  \\\n    ::testcase_ = UnitTest::GetInstance()->RegisterTestCase(  \\\n        new TESTCASE_NAME(testcase_name)(#testcase_name));    \\\nvoid TESTCASE_NAME(testcase_name)::Run()\n\n/*\nRun()后边没有写实现，是为了用宏定义将测试用例放入到 Run 的实现里，例如：\nTEST(AddTestDemo)\n{\nEXPECT_EQ(3, Add(1, 2));\nEXPECT_EQ(2, Add(1, 1));\n}\n上述代码将 { EXPECT_EQ(3, Add(1, 2)); EXPECT_EQ(2, Add(1, 1)); } 接到 Run() 的后面\n*/\n\n\n/*****************************************************************************************/\n\n// 简单测试的宏定义\n// 断言 : 宏定义形式为 EXPECT_* ，符合验证条件的，案例测试通过，否则失败\n// 使用一系列的宏来封装验证条件，分为以下几大类 :\n\n/*\n真假断言\nEXPECT_TRUE  验证条件: Condition 为 true\nEXPECT_FALSE 验证条件: Condition 为 false\n\nExample:\nbool isPrime(int n);         一个判断素数的函数\nEXPECT_TRUE(isPrime(2));     通过\nEXPECT_FALSE(isPrime(4));    通过\nEXPECT_TRUE(isPrime(6));     失败\nEXPECT_FALSE(isPrime(3));    失败\n*/\n#define EXPECT_TRUE(Condition) do {                             \\\n  if (Condition) {                                              \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_TRUE succeeded!\\n\";          \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_TRUE failed!\\n\";               \\\n}} while(0)\n\n#define EXPECT_FALSE(Condition) do {                            \\\n  if (!Condition) {                                             \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_FALSE succeeded!\\n\";         \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \"  EXPECT_FALSE failed!\\n\";             \\\n}} while(0)\n\n/*\n比较断言\nEXPECT_EQ(v1, v2) 验证条件: v1 == v2\nEXPECT_NE(v1, v2) 验证条件: v1 != v2\nEXPECT_LT(v1, v2) 验证条件: v1 <  v2\nEXPECT_LE(v1, v2) 验证条件: v1 <= v2\nEXPECT_GT(v1, v2) 验证条件: v1 >  v2\nEXPECT_GE(v1, v2) 验证条件: v1 >= v2\n\nNote:\n1. 参数应满足 EXPECT_*(Expect, Actual)的格式，左边是期望值，右边是实际值\n2. 在断言失败时，会将期望值与实际值打印出来\n3. 参数值必须是可通过断言的比较操作符进行比较的，参数值还必须支持 << 操作符来\n将值输入到 ostream 中\n4. 这些断言可以用于用户自定义型别，但必须重载相应的比较操作符（如 == 、< 等）\n5. EXPECT_EQ 对指针进行的是地址比较。即比较的是它们是否指向相同的内存地址，\n而不是它们指向的内容是否相等。如果想比较两个 C 字符串(const char*)的值，\n请使用 EXPECT_STREQ 。特别一提的是，要验证一个 C 字符串是否为空(NULL)，\n请使用 EXPECT_STREQ(NULL, c_str)。但是要比较两个 string 对象时，\n应该使用 EXPECT_EQ\n\nExample:\nEXPECT_EQ(3, foo());\nEXPECT_NE(NULL, pointer);\nEXPECT_LT(len, v.size());\n*/\n#define EXPECT_EQ(v1, v2) do { \\\n  if (v1 == v2) {                                               \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_EQ succeeded!\\n\";            \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_EQ failed!\\n\";                 \\\n    std::cout << red << \" Expect:\" << v1 << \"\\n\";               \\\n    std::cout << red << \" Actual:\" << v2 << \"\\n\";               \\\n}} while(0)\n\n#define EXPECT_NE(v1, v2) do {                                  \\\n  if (v1 != v2) {                                               \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n   std::cout << green << \" EXPECT_NE succeeded!\\n\";             \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_NE failed!\\n\";                 \\\n    std::cout << red << \" Expect:\" << v1 << \"\\n\";               \\\n    std::cout << red << \" Actual:\" << v2 << \"\\n\";               \\\n}} while(0)\n\n#define EXPECT_LT(v1, v2) do {                                  \\\n  if (v1 < v2) {                                                \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_LT succeeded!\\n\";            \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_LT failed!\\n\";                 \\\n    std::cout << red << \" Expect:\" << v1 << \"\\n\";               \\\n    std::cout << red << \" Actual:\" << v2 << \"\\n\";               \\\n}} while(0)\n\n#define EXPECT_LE(v1, v2) do {                                  \\\n  if (v1 <= v2) {                                               \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_LE succeeded!\\n\";            \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_LE failed!\\n\";                 \\\n    std::cout << red << \" Expect:\" << v1 << \"\\n\";               \\\n    std::cout << red << \" Actual:\" << v2 << \"\\n\";               \\\n}} while(0)\n\n#define EXPECT_GT(v1, v2) do {                                  \\\n  if (v1 > v2) {                                                \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_GT succeeded!\\n\";            \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_GT failed!\\n\";                 \\\n    std::cout << red << \" Expect:\" << v1 << \"\\n\";               \\\n    std::cout << red << \" Actual:\" << v2 << \"\\n\";               \\\n}} while(0)\n\n#define EXPECT_GE(v1, v2) do {                                  \\\n  if (v1 >= v2) {                                               \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_GE succeeded!\\n\";            \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_GE failed!\\n\";                 \\\n    std::cout << red << \" Expect:\" << v1 << \"\\n\";               \\\n    std::cout << red << \" Actual:\" << v2 << \"\\n\";               \\\n}} while(0)\n\n/*\n字符串比较\nEXPECT_STREQ(s1, s2) 验证条件: 两个 C 字符串有相同的值\nEXPECT_STRNE(s1, s2) 验证条件: 两个 C 字符串有不同的值\n\nNote:\n1. 参数应满足 EXPECT_STR*(Expect, Actual)的格式，左边是期望值，右边是实际值\n2. 该组断言用于比较两个 C 字符串。如果你想要比较两个 string 对象，相应地使用\nEXPECT_EQ、EXPECT_NE 等断言\n3. EXPECT_STREQ 和 EXPECT_STRNE 不接受宽字符串（wchar_t*）\n4. 一个 NULL 指针和一个空字符串会不是一样的\n\nExample:\nchar* s1 = \"\", char* s2 = \"abc\", char* s3 = NULL;\nEXPECT_STREQ(\"abc\", s2);  通过\nEXPECT_STREQ(s1, s3);     失败\nEXPECT_STREQ(NULL, s3);   通过\nEXPECT_STRNE(\" \", s1);    通过\n*/\n\n#define EXPECT_STREQ(s1, s2) do {                                 \\\n  if (s1 == NULL || s2 == NULL) {                                 \\\n    if (s1 == NULL && s2 == NULL) {                               \\\n      UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n      std::cout << green << \" EXPECT_STRED succeeded!\\n\";         \\\n    }                                                             \\\n    else {                                                        \\\n      UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n      UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n      std::cout << red << \" EXPECT_STRED failed!\\n\";              \\\n      if(s1 == NULL) std::cout << \" Expect: NULL\\n\";              \\\n      else std::cout << \" Expect:\\\"\" << s1 << \"\\\"\\n\";             \\\n      if(s2 == NULL) std::cout << \" Actual: NULL\\n\";              \\\n      else std::cout << \" Actual:\\\"\" << s2 << \"\\\"\\n\";             \\\n    }                                                             \\\n  }                                                               \\\n  else if (strcmp(s1, s2) == 0) {                                 \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;          \\\n    std::cout << green << \" EXPECT_STRED succeeded!\\n\";           \\\n  }                                                               \\\n  else {                                                          \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;    \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;          \\\n    std::cout << red << \" EXPECT_STRED failed!\\n\";                \\\n    std::cout << red << \" Expect:\\\"\" << s1 << \"\\\"\\n\";             \\\n    std::cout << red << \" Actual:\\\"\" << s2 << \"\\\"\\n\";             \\\n}} while(0)\n\n#define EXPECT_STRNE(s1, s2) do {                                 \\\n  if (s1 == NULL || s2 == NULL) {                                 \\\n    if (s1 != NULL || s2 != NULL) {                               \\\n      UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n      std::cout << green << \" EXPECT_STRNE succeeded!\\n\";         \\\n    }                                                             \\\n    else {                                                        \\\n      UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n      UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n      std::cout << red << \" EXPECT_STRNE failed!\\n\";              \\\n      if(s1 == NULL) std::cout << \" Expect: NULL\\n\";              \\\n      else std::cout << \" Expect:\\\"\" << s1 << \"\\\"\\n\";             \\\n      if(s2 == NULL) std::cout << \" Actual: NULL\\n\";              \\\n      else std::cout << \" Actual:\\\"\" << s2 << \"\\\"\\n\";             \\\n    }                                                             \\\n  }                                                               \\\n  else if (strcmp(s1, s2) != 0) {                                 \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;          \\\n    std::cout << green << \" EXPECT_STRNE succeeded!\\n\";           \\\n  }                                                               \\\n  else {                                                          \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;    \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;          \\\n    std::cout << red << \" EXPECT_STRNE failed!\\n\";                \\\n    std::cout << red << \" Expect:\\\"\" << s1 << \"\\\"\\n\";             \\\n    std::cout << red << \" Actual:\\\"\" << s2 << \"\\\"\\n\";             \\\n}} while(0)\n\n/*\n指针比较\nEXPECT_PTR_EQ(p1, p2)            验证条件: *p1 == *p2\nEXPECT_PTR_NE(p1, p2)            验证条件: *p1 != *p2\nEXPECT_PTR_RANGE_EQ(p1, p2, len) 验证条件: 任意 i (*p1 + i) == (*p2 + i)  i∈[0,len)\nEXPECT_PTR_RANGE_NE(p1, p2, len) 验证条件: 存在 i (*p1 + i) != (*p2 + i)  i∈[0,len)\n\nNote:\n1. 参数应满足 EXPECT_PTR_*(Expect, Actual)、\nEXPECT_PTR_RANGE_*(Expect, Actual, len)的格式，\n即参数表中期望值在实际值左边\n2. EXPECT_PTR_EQ 比较的是指针所指元素的值，如果要比较\n指针指向的地址是否相等，请用 EXPECT_EQ\n3. EXPECT_PTR_RANGE_* 比较的是从 p1，p2 开始，\n长度为 len 的区间，请确保区间长度有效\n\nExample:\nint a[] = {1,2,3,4,5};\nint b[] = {1,2,3,4,6};\nint *p1 = a, *p2 = b;\nEXPECT_PTR_EQ(p1, p2);                      通过\np1 = a + 4, p2 = b + 4;\nEXPECT_PTR_EQ(p1, p2);                      失败\nEXPECT_PTR_EQ(p1, std::find(a, a + 5, 5));  通过\nEXPECT_PTR_RANGE_EQ(a, b, 5);               失败\nEXPECT_PTR_RANGE_EQ(a, b, 4);               通过\n*/\n#define EXPECT_PTR_EQ(p1, p2) do {                              \\\n  if (*p1 == *p2) {                                             \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_PTR_EQ succeeded!\\n\";        \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_PTR_EQ failed!\\n\";             \\\n    std::cout << red << \" Expect:\" << *p1 << \"\\n\";              \\\n    std::cout << red << \" Actual:\" << *p2 << \"\\n\";              \\\n}} while(0)\n\n#define EXPECT_PTR_NE(p1, p2) do {                              \\\n  if (*p1 != *p2) {                                             \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_PTR_NE succeeded!\\n\";        \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_PTR_NE failed!\\n\";             \\\n    std::cout << red << \" Expect:\" << *p1 << \"\\n\";              \\\n    std::cout << red << \" Actual:\" << *p2 << \"\\n\";              \\\n}} while(0)\n\n#define EXPECT_PTR_RANGE_EQ(p1, p2, len) do {                   \\\n  if (std::equal(p1, p1 + len, p2)) {                           \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_PTR_RANGE_EQ succeeded!\\n\";  \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_PTR_RANGE_EQ failed!\\n\";       \\\n}} while(0)\n\n#define EXPECT_PTR_RANGE_NE(p1, p2, len) do {                   \\\n  if (!std::equal(p1, p1 + len, p2)) {                          \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;        \\\n    std::cout << green << \" EXPECT_PTR_RANGE_NE succeeded!\\n\";  \\\n  }                                                             \\\n  else {                                                        \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;  \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;        \\\n    std::cout << red << \" EXPECT_PTR_RANGE_NE failed!\\n\";       \\\n}} while(0)\n\n/*\n容器比较\nEXPECT_CON_EQ(c1, c2) 验证条件: c1 == c2\nEXPECT_CON_NE(c1, c2) 验证条件: c1 != c2\n\nNote:\n1. 容器可以是 STL 容器，自定义的容器，或者数组，但不可以是指针\n2. 容器的数据类型要能够进行比较，类型一致或可以发生隐式转换\n3. EXPECT_CON_EQ 测试失败时，会打印首次不相等的两个值\n\nExample:\nint arr[] = {1,2,3};\nstd::vector<int> v1{1, 2, 3};\nstd::vector<int> v2{2, 3, 4};\nmystl::vector<long> v3(arr, arr + 3);\nEXPECT_CON_NE(v1, v2)   ok\nEXPECT_CON_EQ(arr, v1)  ok\nEXPECT_CON_EQ(v1, v3)   ok\n*/\n#define EXPECT_CON_EQ(c1, c2) do {                                  \\\n  auto first1 = std::begin(c1), last1 = std::end(c1);               \\\n  auto first2 = std::begin(c2), last2 = std::end(c2);               \\\n  for (; first1 != last1 && first2 != last2; ++first1, ++first2) {  \\\n    if (*first1 != *first2)  break;                                 \\\n  }                                                                 \\\n  if (first1 == last1 && first2 == last2) {                         \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;            \\\n    std::cout << green << \" EXPECT_CON_EQ succeeded!\\n\";            \\\n  }                                                                 \\\n  else {                                                            \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;      \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;            \\\n    std::cout << red << \" EXPECT_CON_EQ failed!\\n\";                 \\\n    std::cout << red << \" Expect:\" << *first1 << \"\\n\";              \\\n    std::cout << red << \" Actual:\" << *first2 << \"\\n\";              \\\n}} while(0)\n\n#define EXPECT_CON_NE(c1, c2) do {                                  \\\n  auto first1 = std::begin(c1), last1 = std::end(c1);               \\\n  auto first2 = std::begin(c2), last2 = std::end(c2);               \\\n  for (; first1 != last1 && first2 != last2; ++first1, ++first2) {  \\\n    if (*first1 != *first2)  break;                                 \\\n  }                                                                 \\\n  if (first1 != last1 || first2 != last2) {                         \\\n    UnitTest::GetInstance()->CurrentTestCase->nPassed++;            \\\n    std::cout << green << \" EXPECT_CON_NE succeeded!\\n\";            \\\n  }                                                                 \\\n  else {                                                            \\\n    UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0;      \\\n    UnitTest::GetInstance()->CurrentTestCase->nFailed++;            \\\n    std::cout << red << \" EXPECT_CON_NE failed!\\n\";                 \\\n}} while(0)\n\n/*****************************************************************************************/\n// 常用的宏定义\n\n// 不同情况的测试数量级\n#if defined(_DEBUG) || defined(DEBUG)\n#define LEN1    10000\n#define LEN2    100000\n#define LEN3    1000000\n#else\n#define LEN1    100000\n#define LEN2    1000000\n#define LEN3    10000000\n#endif\n\n#define SCALE_LLL(N) (N * 20)\n#define SCALE_LL(N)  (N * 10)\n#define SCALE_L(N)   (N * 5)\n#define SCALE_M(N)   (N)\n#define SCALE_S(N)   (N / 5)\n#define SCALE_SS(N)  (N / 10)\n#define SCALE_SSS(N) (N / 20)\n\n#define WIDE    14\n\n// 输出通过提示\n#define PASSED    std::cout << \"[ PASSED ]\\n\"\n\n// 遍历输出容器\n#define COUT(container) do {                             \\\n  std::string con_name = #container;                     \\\n  std::cout << \" \" << con_name << \" :\";                  \\\n  for (auto it : container)                              \\\n    std::cout << \" \" << it;                              \\\n  std::cout << \"\\n\";                                     \\\n} while(0)\n\n#define STR_COUT(str) do {                               \\\n  std::string str_name = #str;                           \\\n  std::cout << \" \" << str_name << \" : \" << str << \"\\n\";  \\\n} while(0)\n\n// 输出容器调用函数后的结果\n#define FUN_AFTER(con, fun) do {                         \\\n  std::string fun_name = #fun;                           \\\n  std::cout << \" After \" << fun_name << \" :\\n\";          \\\n  fun;                                                   \\\n  COUT(con);                                             \\\n} while(0)\n\n#define STR_FUN_AFTER(str, fun) do {                     \\\n  std::string fun_name = #fun;                           \\\n  std::cout << \" After \" << fun_name << \" :\\n\";          \\\n  fun;                                                   \\\n  STR_COUT(str);                                         \\\n} while(0)\n\n// 输出容器调用函数的值\n#define FUN_VALUE(fun) do {                              \\\n  std::string fun_name = #fun;                           \\\n  std::cout << \" \" << fun_name << \" : \" << fun << \"\\n\";  \\\n} while(0)\n\n// 输出测试数量级\nvoid test_len(size_t len1, size_t len2, size_t len3, size_t wide)\n{\n  std::string str1, str2, str3;\n  std::stringstream ss;\n  ss << len1 << \" \" << len2 << \" \" << len3;\n  ss >> str1 >> str2 >> str3;\n  str1 += \"   |\";\n  std::cout << std::setw(wide) << str1;\n  str2 += \"   |\";\n  std::cout << std::setw(wide) << str2;\n  str3 += \"   |\";\n  std::cout << std::setw(wide) << str3 << \"\\n\";\n}\n\n#define TEST_LEN(len1, len2, len3, wide) \\\n  test_len(len1, len2, len3, wide)\n\n// 常用测试性能的宏\n#define FUN_TEST_FORMAT1(mode, fun, arg, count) do {         \\\n  srand((int)time(0));                                       \\\n  clock_t start, end;                                        \\\n  mode c;                                                    \\\n  char buf[10];                                              \\\n  start = clock();                                           \\\n  for (size_t i = 0; i < count; ++i)                         \\\n    c.fun(arg);                                              \\\n  end = clock();                                             \\\n  int n = static_cast<int>(static_cast<double>(end - start)  \\\n      / CLOCKS_PER_SEC * 1000);                              \\\n  std::snprintf(buf, sizeof(buf), \"%d\", n);                  \\\n  std::string t = buf;                                       \\\n  t += \"ms    |\";                                            \\\n  std::cout << std::setw(WIDE) << t;                         \\\n} while(0)\n\n#define FUN_TEST_FORMAT2(mode, fun, arg1, arg2, count) do {  \\\n  srand((int)time(0));                                       \\\n  clock_t start, end;                                        \\\n  mode c;                                                    \\\n  char buf[10];                                              \\\n  start = clock();                                           \\\n  for (size_t i = 0; i < count; ++i)                         \\\n    c.fun(c.arg1(), arg2);                                   \\\n  end = clock();                                             \\\n  int n = static_cast<int>(static_cast<double>(end - start)  \\\n      / CLOCKS_PER_SEC * 1000);                              \\\n  std::snprintf(buf, sizeof(buf), \"%d\", n);                  \\\n  std::string t = buf;                                       \\\n  t += \"ms    |\";                                            \\\n  std::cout << std::setw(WIDE) << t;                         \\\n} while(0)\n\n#define LIST_SORT_DO_TEST(mode, count) do {                  \\\n  srand((int)time(0));                                       \\\n  clock_t start, end;                                        \\\n  mode::list<int> l;                                         \\\n  char buf[10];                                              \\\n  for (size_t i = 0; i < count; ++i)                         \\\n    l.insert(l.end(), rand());                               \\\n  start = clock();                                           \\\n  l.sort();                                                  \\\n  end = clock();                                             \\\n  int n = static_cast<int>(static_cast<double>(end - start)  \\\n      / CLOCKS_PER_SEC * 1000);                              \\\n  std::snprintf(buf, sizeof(buf), \"%d\", n);                  \\\n  std::string t = buf;                                       \\\n  t += \"ms    |\";                                            \\\n  std::cout << std::setw(WIDE) << t;                         \\\n} while(0)\n\n#define MAP_EMPLACE_DO_TEST(mode, con, count) do {           \\\n  srand((int)time(0));                                       \\\n  clock_t start, end;                                        \\\n  mode::con<int, int> c;                                     \\\n  char buf[10];                                              \\\n  start = clock();                                           \\\n  for (size_t i = 0; i < count; ++i)                         \\\n    c.emplace(mode::make_pair(rand(), rand()));              \\\n  end = clock();                                             \\\n  int n = static_cast<int>(static_cast<double>(end - start)  \\\n      / CLOCKS_PER_SEC * 1000);                              \\\n  std::snprintf(buf, sizeof(buf), \"%d\", n);                  \\\n  std::string t = buf;                                       \\\n  t += \"ms    |\";                                            \\\n  std::cout << std::setw(WIDE) << t;                         \\\n} while(0)\n\n// 重构重复代码\n#define CON_TEST_P1(con, fun, arg, len1, len2, len3)         \\\n  TEST_LEN(len1, len2, len3, WIDE);                          \\\n  std::cout << \"|         std         |\";                    \\\n  FUN_TEST_FORMAT1(std::con, fun, arg, len1);                \\\n  FUN_TEST_FORMAT1(std::con, fun, arg, len2);                \\\n  FUN_TEST_FORMAT1(std::con, fun, arg, len3);                \\\n  std::cout << \"\\n|        mystl        |\";                  \\\n  FUN_TEST_FORMAT1(mystl::con, fun, arg, len1);              \\\n  FUN_TEST_FORMAT1(mystl::con, fun, arg, len2);              \\\n  FUN_TEST_FORMAT1(mystl::con, fun, arg, len3);    \n\n#define CON_TEST_P2(con, fun, arg1, arg2, len1, len2, len3)  \\\n  TEST_LEN(len1, len2, len3, WIDE);                          \\\n  std::cout << \"|         std         |\";                    \\\n  FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len1);         \\\n  FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len2);         \\\n  FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len3);         \\\n  std::cout << \"\\n|        mystl        |\";                  \\\n  FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len1);       \\\n  FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len2);       \\\n  FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len3);    \n\n#define MAP_EMPLACE_TEST(con, len1, len2, len3)              \\\n  TEST_LEN(len1, len2, len3, WIDE);                          \\\n  std::cout << \"|         std         |\";                    \\\n  MAP_EMPLACE_DO_TEST(std, con, len1);                       \\\n  MAP_EMPLACE_DO_TEST(std, con, len2);                       \\\n  MAP_EMPLACE_DO_TEST(std, con, len3);                       \\\n  std::cout << \"\\n|        mystl        |\";                  \\\n  MAP_EMPLACE_DO_TEST(mystl, con, len1);                     \\\n  MAP_EMPLACE_DO_TEST(mystl, con, len2);                     \\\n  MAP_EMPLACE_DO_TEST(mystl, con, len3);\n\n#define LIST_SORT_TEST(len1, len2, len3)                     \\\n  TEST_LEN(len1, len2, len3, WIDE);                          \\\n  std::cout << \"|         std         |\";                    \\\n  LIST_SORT_DO_TEST(std, len1);                              \\\n  LIST_SORT_DO_TEST(std, len2);                              \\\n  LIST_SORT_DO_TEST(std, len3);                              \\\n  std::cout << \"\\n|        mystl        |\";                  \\\n  LIST_SORT_DO_TEST(mystl, len1);                            \\\n  LIST_SORT_DO_TEST(mystl, len2);                            \\\n  LIST_SORT_DO_TEST(mystl, len3);\n\n// 简单测试的宏定义\n#define TEST(testcase_name) \\\n  MYTINYSTL_TEST_(testcase_name)\n\n// 运行所有测试案例\n#define RUN_ALL_TESTS() \\\n  mystl::test::UnitTest::GetInstance()->Run()\n\n// 是否开启性能测试\n#ifndef PERFORMANCE_TEST_ON\n#define PERFORMANCE_TEST_ON 1\n#endif // !PERFORMANCE_TEST_ON\n\n// 是否开启大数据量测试\n#ifndef LARGER_TEST_DATA_ON\n#define LARGER_TEST_DATA_ON 0\n#endif // !LARGER_TEST_DATA_ON\n\n}    // namespace test\n}    // namespace mystl\n#endif // !MYTINYSTL_TEST_H_\n\n"
  },
  {
    "path": "Test/unordered_map_test.h",
    "content": "﻿#ifndef MYTINYSTL_UNORDERED_MAP_TEST_H_\n#define MYTINYSTL_UNORDERED_MAP_TEST_H_\n\n// unordered_map test : 测试 unordered_map, unordered_multimap 的接口与它们 insert 的性能\n\n#include <unordered_map>\n\n#include \"../MyTinySTL/unordered_map.h\"\n#include \"map_test.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace unordered_map_test\n{\n\nvoid unordered_map_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[-------------- Run container test : unordered_map -------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  mystl::vector<PAIR> v;\n  for (int i = 0; i < 5; ++i)\n    v.push_back(PAIR(5 - i, 5 - i));\n  mystl::unordered_map<int, int> um1;\n  mystl::unordered_map<int, int> um2(520);\n  mystl::unordered_map<int, int> um3(520, mystl::hash<int>());\n  mystl::unordered_map<int, int> um4(520, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_map<int, int> um5(v.begin(), v.end());\n  mystl::unordered_map<int, int> um6(v.begin(), v.end(), 100);\n  mystl::unordered_map<int, int> um7(v.begin(), v.end(), 100, mystl::hash<int>());\n  mystl::unordered_map<int, int> um8(v.begin(), v.end(), 100, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_map<int, int> um9(um5);\n  mystl::unordered_map<int, int> um10(std::move(um5));\n  mystl::unordered_map<int, int> um11;\n  um11 = um6;\n  mystl::unordered_map<int, int> um12;\n  um12 = std::move(um6);\n  mystl::unordered_map<int, int> um13{ PAIR(1,1),PAIR(2,3),PAIR(3,3) };\n  mystl::unordered_map<int, int> um14;\n  um14 = { PAIR(1,1),PAIR(2,3),PAIR(3,3) };\n\n  MAP_FUN_AFTER(um1, um1.emplace(1, 1));\n  MAP_FUN_AFTER(um1, um1.emplace_hint(um1.begin(), 1, 2));\n  MAP_FUN_AFTER(um1, um1.insert(PAIR(2, 2)));\n  MAP_FUN_AFTER(um1, um1.insert(um1.end(), PAIR(3, 3)));\n  MAP_FUN_AFTER(um1, um1.insert(v.begin(), v.end()));\n  MAP_FUN_AFTER(um1, um1.erase(um1.begin()));\n  MAP_FUN_AFTER(um1, um1.erase(um1.begin(), um1.find(3)));\n  MAP_FUN_AFTER(um1, um1.erase(1));\n  std::cout << std::boolalpha;\n  FUN_VALUE(um1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(um1.size());\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.max_bucket_count());\n  FUN_VALUE(um1.bucket(1));\n  FUN_VALUE(um1.bucket_size(um1.bucket(5)));\n  MAP_FUN_AFTER(um1, um1.clear());\n  MAP_FUN_AFTER(um1, um1.swap(um7));\n  MAP_VALUE(*um1.begin());\n  FUN_VALUE(um1.at(1));\n  FUN_VALUE(um1[1]);\n  std::cout << std::boolalpha;\n  FUN_VALUE(um1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(um1.size());\n  FUN_VALUE(um1.max_size());\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.max_bucket_count());\n  FUN_VALUE(um1.bucket(1));\n  FUN_VALUE(um1.bucket_size(um1.bucket(1)));\n  MAP_FUN_AFTER(um1, um1.reserve(1000));\n  FUN_VALUE(um1.size());\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.bucket_size(1));\n  FUN_VALUE(um1.bucket_size(2));\n  FUN_VALUE(um1.bucket_size(3));\n  MAP_FUN_AFTER(um1, um1.rehash(150));\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.count(1));\n  MAP_VALUE(*um1.find(3));\n  auto first = *um1.equal_range(3).first;\n  auto second = *um1.equal_range(3).second;\n  std::cout << \" um1.equal_range(3) : from <\" << first.first << \", \" << first.second\n    << \"> to <\" << second.first << \", \" << second.second << \">\" << std::endl;\n  FUN_VALUE(um1.load_factor());\n  FUN_VALUE(um1.max_load_factor());\n  MAP_FUN_AFTER(um1, um1.max_load_factor(1.5f));\n  FUN_VALUE(um1.max_load_factor());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  MAP_EMPLACE_TEST(unordered_map, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#else\n  MAP_EMPLACE_TEST(unordered_map, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[-------------- End container test : unordered_map -------------]\" << std::endl;\n}\n\nvoid unordered_multimap_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[----------- Run container test : unordered_multimap -----------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  mystl::vector<PAIR> v;\n  for (int i = 0; i < 5; ++i)\n    v.push_back(PAIR(5 - i, 5 - i));\n  mystl::unordered_multimap<int, int> um1;\n  mystl::unordered_multimap<int, int> um2(520);\n  mystl::unordered_multimap<int, int> um3(520, mystl::hash<int>());\n  mystl::unordered_multimap<int, int> um4(520, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_multimap<int, int> um5(v.begin(), v.end());\n  mystl::unordered_multimap<int, int> um6(v.begin(), v.end(), 100);\n  mystl::unordered_multimap<int, int> um7(v.begin(), v.end(), 100, mystl::hash<int>());\n  mystl::unordered_multimap<int, int> um8(v.begin(), v.end(), 100, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_multimap<int, int> um9(um5);\n  mystl::unordered_multimap<int, int> um10(std::move(um5));\n  mystl::unordered_multimap<int, int> um11;\n  um11 = um6;\n  mystl::unordered_multimap<int, int> um12;\n  um12 = std::move(um6);\n  mystl::unordered_multimap<int, int> um13{ PAIR(1,1),PAIR(2,3),PAIR(3,3) };\n  mystl::unordered_multimap<int, int> um14;\n  um14 = { PAIR(1,1),PAIR(2,3),PAIR(3,3) };\n\n  MAP_FUN_AFTER(um1, um1.emplace(1, 1));\n  MAP_FUN_AFTER(um1, um1.emplace_hint(um1.begin(), 1, 2));\n  MAP_FUN_AFTER(um1, um1.insert(PAIR(2, 2)));\n  MAP_FUN_AFTER(um1, um1.insert(um1.end(), PAIR(3, 3)));\n  MAP_FUN_AFTER(um1, um1.insert(v.begin(), v.end()));\n  MAP_FUN_AFTER(um1, um1.erase(um1.begin()));\n  MAP_FUN_AFTER(um1, um1.erase(um1.begin(), um1.find(3)));\n  MAP_FUN_AFTER(um1, um1.erase(1));\n  std::cout << std::boolalpha;\n  FUN_VALUE(um1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(um1.size());\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.max_bucket_count());\n  FUN_VALUE(um1.bucket(1));\n  FUN_VALUE(um1.bucket_size(um1.bucket(5)));\n  MAP_FUN_AFTER(um1, um1.clear());\n  MAP_FUN_AFTER(um1, um1.swap(um7));\n  MAP_VALUE(*um1.begin());\n  std::cout << std::boolalpha;\n  FUN_VALUE(um1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(um1.size());\n  FUN_VALUE(um1.max_size());\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.max_bucket_count());\n  FUN_VALUE(um1.bucket(1));\n  FUN_VALUE(um1.bucket_size(um1.bucket(1)));\n  MAP_FUN_AFTER(um1, um1.reserve(1000));\n  FUN_VALUE(um1.size());\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.bucket_size(1));\n  FUN_VALUE(um1.bucket_size(2));\n  FUN_VALUE(um1.bucket_size(3));\n  MAP_FUN_AFTER(um1, um1.rehash(150));\n  FUN_VALUE(um1.bucket_count());\n  FUN_VALUE(um1.count(1));\n  MAP_VALUE(*um1.find(3));\n  auto first = *um1.equal_range(3).first;\n  auto second = *um1.equal_range(3).second;\n  std::cout << \" um1.equal_range(3) : from <\" << first.first << \", \" << first.second\n    << \"> to <\" << second.first << \", \" << second.second << \">\" << std::endl;\n  FUN_VALUE(um1.load_factor());\n  FUN_VALUE(um1.max_load_factor());\n  MAP_FUN_AFTER(um1, um1.max_load_factor(1.5f));\n  FUN_VALUE(um1.max_load_factor());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  MAP_EMPLACE_TEST(unordered_multimap, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#else\n  MAP_EMPLACE_TEST(unordered_multimap, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[----------- End container test : unordered_multimap -----------]\" << std::endl;\n}\n\n} // namespace unordered_map_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_UNORDERED_MAP_TEST_H_\n\n"
  },
  {
    "path": "Test/unordered_set_test.h",
    "content": "﻿#ifndef MYTINYSTL_UNORDERED_SET_TEST_H_\n#define MYTINYSTL_UNORDERED_SET_TEST_H_\n\n// unordered_set test : 测试 unordered_set, unordered_multiset 的接口与它们 insert 的性能\n\n#include <unordered_set>\n\n#include \"../MyTinySTL/unordered_set.h\"\n#include \"set_test.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace unordered_set_test\n{\n\nvoid unordered_set_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[-------------- Run container test : unordered_set -------------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 5,4,3,2,1 };\n  mystl::unordered_set<int> us1;\n  mystl::unordered_set<int> us2(520);\n  mystl::unordered_set<int> us3(520, mystl::hash<int>());\n  mystl::unordered_set<int> us4(520, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_set<int> us5(a, a + 5);\n  mystl::unordered_set<int> us6(a, a + 5, 100);\n  mystl::unordered_set<int> us7(a, a + 5, 100, mystl::hash<int>());\n  mystl::unordered_set<int> us8(a, a + 5, 100, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_set<int> us9(us5);\n  mystl::unordered_set<int> us10(std::move(us5));\n  mystl::unordered_set<int> us11;\n  us11 = us6;\n  mystl::unordered_set<int> us12;\n  us12 = std::move(us6);\n  mystl::unordered_set<int> us13{ 1,2,3,4,5 };\n  mystl::unordered_set<int> us14;\n  us13 = { 1,2,3,4,5 };\n\n  FUN_AFTER(us1, us1.emplace(1));\n  FUN_AFTER(us1, us1.emplace_hint(us1.end(), 2));\n  FUN_AFTER(us1, us1.insert(5));\n  FUN_AFTER(us1, us1.insert(us1.begin(), 5));\n  FUN_AFTER(us1, us1.insert(a, a + 5));\n  FUN_AFTER(us1, us1.erase(us1.begin()));\n  FUN_AFTER(us1, us1.erase(us1.begin(), us1.find(3)));\n  FUN_AFTER(us1, us1.erase(1));\n  std::cout << std::boolalpha;\n  FUN_VALUE(us1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(us1.size());\n  FUN_VALUE(us1.bucket_count());\n  FUN_VALUE(us1.max_bucket_count());\n  FUN_VALUE(us1.bucket(1));\n  FUN_VALUE(us1.bucket_size(us1.bucket(5)));\n  FUN_AFTER(us1, us1.clear());\n  FUN_AFTER(us1, us1.swap(us7));\n  FUN_VALUE(*us1.begin());\n  std::cout << std::boolalpha;\n  FUN_VALUE(us1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(us1.size());\n  FUN_VALUE(us1.max_size());\n  FUN_VALUE(us1.bucket_count());\n  FUN_AFTER(us1, us1.reserve(1000));\n  FUN_VALUE(*us1.begin(us1.bucket(1)));\n  FUN_VALUE(us1.size());\n  FUN_VALUE(us1.bucket_count());\n  FUN_VALUE(us1.bucket_size(1));\n  FUN_VALUE(us1.bucket_size(2));\n  FUN_VALUE(us1.bucket_size(3));\n  FUN_AFTER(us1, us1.rehash(150));\n  FUN_VALUE(us1.bucket_count());\n  FUN_VALUE(us1.count(1));\n  FUN_VALUE(*us1.find(3));\n  auto first = *us1.equal_range(3).first;\n  auto second = *us1.equal_range(3).second;\n  std::cout << \" us1.equal_range(3) : from \" << first << \" to \" << second << std::endl;\n  FUN_VALUE(us1.load_factor());\n  FUN_VALUE(us1.max_load_factor());\n  FUN_AFTER(us1, us1.max_load_factor(1.5f));\n  FUN_VALUE(us1.max_load_factor());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(unordered_set<int>, emplace, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#else\n  CON_TEST_P1(unordered_set<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[-------------- End container test : unordered_set -------------]\" << std::endl;\n}\n\nvoid unordered_multiset_test()\n{\n  std::cout << \"[===============================================================]\" << std::endl;\n  std::cout << \"[------------ Run container test : unordered_multiset ----------]\" << std::endl;\n  std::cout << \"[-------------------------- API test ---------------------------]\" << std::endl;\n  int a[] = { 5,4,3,2,1 };\n  mystl::unordered_multiset<int> us1;\n  mystl::unordered_multiset<int> us2(520);\n  mystl::unordered_multiset<int> us3(520, mystl::hash<int>());\n  mystl::unordered_multiset<int> us4(520, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_multiset<int> us5(a, a + 5);\n  mystl::unordered_multiset<int> us6(a, a + 5, 100);\n  mystl::unordered_multiset<int> us7(a, a + 5, 100, mystl::hash<int>());\n  mystl::unordered_multiset<int> us8(a, a + 5, 100, mystl::hash<int>(), mystl::equal_to<int>());\n  mystl::unordered_multiset<int> us9(us5);\n  mystl::unordered_multiset<int> us10(std::move(us5));\n  mystl::unordered_multiset<int> us11;\n  us11 = us6;\n  mystl::unordered_multiset<int> us12;\n  us12 = std::move(us6);\n  mystl::unordered_multiset<int> us13{ 1,2,3,4,5 };\n  mystl::unordered_multiset<int> us14;\n  us14 = { 1,2,3,4,5 };\n\n  FUN_AFTER(us1, us1.emplace(1));\n  FUN_AFTER(us1, us1.emplace_hint(us1.end(), 2));\n  FUN_AFTER(us1, us1.insert(5));\n  FUN_AFTER(us1, us1.insert(us1.begin(), 5));\n  FUN_AFTER(us1, us1.insert(a, a + 5));\n  FUN_AFTER(us1, us1.erase(us1.begin()));\n  FUN_AFTER(us1, us1.erase(us1.begin(), us1.find(3)));\n  FUN_AFTER(us1, us1.erase(1));\n  std::cout << std::boolalpha;\n  FUN_VALUE(us1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(us1.size());\n  FUN_VALUE(us1.bucket_count());\n  FUN_VALUE(us1.max_bucket_count());\n  FUN_VALUE(us1.bucket(1));\n  FUN_VALUE(us1.bucket_size(us1.bucket(5)));\n  FUN_AFTER(us1, us1.clear());\n  FUN_AFTER(us1, us1.swap(us7));\n  FUN_VALUE(*us1.begin());\n  std::cout << std::boolalpha;\n  FUN_VALUE(us1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(us1.size());\n  FUN_VALUE(us1.max_size());\n  FUN_VALUE(us1.bucket_count());\n  FUN_AFTER(us1, us1.reserve(1000));\n  FUN_VALUE(*us1.begin(us1.bucket(1)));\n  FUN_VALUE(us1.size());\n  FUN_VALUE(us1.bucket_count());\n  FUN_VALUE(us1.bucket_size(1));\n  FUN_VALUE(us1.bucket_size(2));\n  FUN_VALUE(us1.bucket_size(3));\n  FUN_AFTER(us1, us1.rehash(150));\n  FUN_VALUE(us1.bucket_count());\n  FUN_VALUE(us1.count(1));\n  FUN_VALUE(*us1.find(3));\n  auto first = *us1.equal_range(3).first;\n  auto second = *us1.equal_range(3).second;\n  std::cout << \" us1.equal_range(3) : from \" << first << \" to \" << second << std::endl;\n  FUN_VALUE(us1.load_factor());\n  FUN_VALUE(us1.max_load_factor());\n  FUN_AFTER(us1, us1.max_load_factor(1.5f));\n  FUN_VALUE(us1.max_load_factor());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\" << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  std::cout << \"|       emplace       |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(unordered_multiset<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));\n#else\n  CON_TEST_P1(unordered_multiset<int>, emplace, rand(), SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));\n#endif\n  std::cout << std::endl;\n  std::cout << \"|---------------------|-------------|-------------|-------------|\" << std::endl;\n  PASSED;\n#endif\n  std::cout << \"[------------ End container test : unordered_multiset ----------]\" << std::endl;\n}\n\n} // namespace unordered_set_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_UNORDERED_SET_TEST_H_\n\n"
  },
  {
    "path": "Test/vector_test.h",
    "content": "﻿#ifndef MYTINYSTL_VECTOR_TEST_H_\n#define MYTINYSTL_VECTOR_TEST_H_\n\n// vector test : 测试 vector 的接口与 push_back 的性能\n\n#include <vector>\n\n#include \"../MyTinySTL/vector.h\"\n#include \"test.h\"\n\nnamespace mystl\n{\nnamespace test\n{\nnamespace vector_test\n{\n\nvoid vector_test()\n{\n  std::cout << \"[===============================================================]\\n\";\n  std::cout << \"[----------------- Run container test : vector -----------------]\\n\";\n  std::cout << \"[-------------------------- API test ---------------------------]\\n\";\n  int a[] = { 1,2,3,4,5 };\n  mystl::vector<int> v1;\n  mystl::vector<int> v2(10);\n  mystl::vector<int> v3(10, 1);\n  mystl::vector<int> v4(a, a + 5);\n  mystl::vector<int> v5(v2);\n  mystl::vector<int> v6(std::move(v2));\n  mystl::vector<int> v7{ 1,2,3,4,5,6,7,8,9 };\n  mystl::vector<int> v8, v9, v10;\n  v8 = v3;\n  v9 = std::move(v3);\n  v10 = { 1,2,3,4,5,6,7,8,9 };\n\n  FUN_AFTER(v1, v1.assign(8, 8));\n  FUN_AFTER(v1, v1.assign(a, a + 5));\n  FUN_AFTER(v1, v1.emplace(v1.begin(), 0));\n  FUN_AFTER(v1, v1.emplace_back(6));\n  FUN_AFTER(v1, v1.push_back(6));\n  FUN_AFTER(v1, v1.insert(v1.end(), 7));\n  FUN_AFTER(v1, v1.insert(v1.begin() + 3, 2, 3));\n  FUN_AFTER(v1, v1.insert(v1.begin(), a, a + 5));\n  FUN_AFTER(v1, v1.pop_back());\n  FUN_AFTER(v1, v1.erase(v1.begin()));\n  FUN_AFTER(v1, v1.erase(v1.begin(), v1.begin() + 2));\n  FUN_AFTER(v1, v1.reverse());\n  FUN_AFTER(v1, v1.swap(v4));\n  FUN_VALUE(*v1.begin());\n  FUN_VALUE(*(v1.end() - 1));\n  FUN_VALUE(*v1.rbegin());\n  FUN_VALUE(*(v1.rend() - 1));\n  FUN_VALUE(v1.front());\n  FUN_VALUE(v1.back());\n  FUN_VALUE(v1[0]);\n  FUN_VALUE(v1.at(1));\n  int* p = v1.data();\n  *p = 10;\n  *++p = 20;\n  p[1] = 30;\n  std::cout << \" After change v1.data() :\" << \"\\n\";\n  COUT(v1);\n  std::cout << std::boolalpha;\n  FUN_VALUE(v1.empty());\n  std::cout << std::noboolalpha;\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.max_size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.resize(10));\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.shrink_to_fit());\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.resize(6, 6));\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.shrink_to_fit());\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.clear());\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.reserve(5));\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.reserve(20));\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  FUN_AFTER(v1, v1.shrink_to_fit());\n  FUN_VALUE(v1.size());\n  FUN_VALUE(v1.capacity());\n  PASSED;\n#if PERFORMANCE_TEST_ON\n  std::cout << \"[--------------------- Performance Testing ---------------------]\\n\";\n  std::cout << \"|---------------------|-------------|-------------|-------------|\\n\";\n  std::cout << \"|      push_back      |\";\n#if LARGER_TEST_DATA_ON\n  CON_TEST_P1(vector<int>, push_back, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));\n#else\n  CON_TEST_P1(vector<int>, push_back, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));\n#endif\n  std::cout << \"\\n\";\n  std::cout << \"|---------------------|-------------|-------------|-------------|\\n\";\n  PASSED;\n#endif\n  std::cout << \"[----------------- End container test : vector -----------------]\\n\";\n}\n\n} // namespace vector_test\n} // namespace test\n} // namespace mystl\n#endif // !MYTINYSTL_VECTOR_TEST_H_\n\n"
  },
  {
    "path": "appveyor.yml",
    "content": "version: 2.0.1{build}\n\nbranches:\n  only:\n    - master\n  \nimage: \n  - Visual Studio 2015\n  - Visual Studio 2017\n  \nconfiguration: \n  - Release\n\nbuild:\n  parallel: true\n  project: MSVC\\MyTinySTL_VS2015.sln\n  \ntest_script:\n  - cmd: cd .\\MSVC\\x64\\Release\\\n  - cmd: MyTinySTL.exe\n\n"
  }
]