diff --git a/.clang-format b/.clang-format index 0cda88089..363922fdb 100644 --- a/.clang-format +++ b/.clang-format @@ -1,136 +1,395 @@ +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). +# +# CMakeLists.txt for Simple-XX/SimpleKernel. + --- -Language: Cpp +# @version clang-format version 15 +# @see https://clang.llvm.org/docs/ClangFormatStyleOptions.html + +# 访问说明符 public/private 的偏移,与类对齐 AccessModifierOffset: -4 +# ( 后的参数对齐,与 ( 对齐 AlignAfterOpenBracket: Align -AlignConsecutiveMacros: false -AlignConsecutiveAssignments: true -AlignConsecutiveDeclarations: true -AlignEscapedNewlines: Right -AlignOperands: true +# 结构体初始化对齐,右对齐 +AlignArrayOfStructures: Right +# 连续赋值对齐 +AlignConsecutiveAssignments: + # 允许 + Enabled: true + # 忽略空行 + AcrossEmptyLines: true + # 忽略注释 + AcrossComments: true + # 忽略混合运算符 + AlignCompound: true + # 填充运算符 + PadOperators: true +# 位域对齐 +AlignConsecutiveBitFields: + # 允许 + Enabled: true + # 忽略空行 + AcrossEmptyLines: true + # 忽略注释 + AcrossComments: true + # 忽略混合运算符 + AlignCompound: true + # 填充运算符 + PadOperators: true +# 连续声明对齐,忽略空行/注释 +AlignConsecutiveDeclarations: + # 允许 + Enabled: true + # 忽略空行 + AcrossEmptyLines: true + # 忽略注释 + AcrossComments: true + # 忽略混合运算符 + AlignCompound: true + # 填充运算符 + PadOperators: true +# 连续宏定义对齐,忽略空行/注释 +AlignConsecutiveMacros: + # 允许 + Enabled: true + # 忽略空行 + AcrossEmptyLines: true + # 忽略注释 + AcrossComments: true + # 忽略混合运算符 + AlignCompound: true + # 填充运算符 + PadOperators: true +# 换行符号左对齐 +AlignEscapedNewlines: Left +# 操作符对齐,与 BreakBeforeBinaryOperators 共同生效 +AlignOperands: AlignAfterOperator +# 行后注释对齐 AlignTrailingComments: true +# 尽量将函数调用/初始化的所有参数放在同一行,禁用 AllowAllArgumentsOnNextLine: false -AllowAllConstructorInitializersOnNextLine: true +# 尽量将函数声明的参数放在同一行 AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: true +# 将 while (true) {} 中的 {} 合并为一行,禁用 +AllowShortBlocksOnASingleLine: Never +# 将 switch case: 中的 case: 合并为一行,禁用 AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: false -AllowShortLambdasOnASingleLine: false -AllowShortIfStatementsOnASingleLine: false +# 将枚举类型合并为一行,禁用 +AllowShortEnumsOnASingleLine: false +# 将短函数合并为一行,禁用 +AllowShortFunctionsOnASingleLine: None +# 将短语句合并为一行,禁用 +AllowShortIfStatementsOnASingleLine: Never +# 将 lambda 表达式合并为一行,禁用 +AllowShortLambdasOnASingleLine: None +# 将短循环合并为一行,禁用 AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None +# 将在返回类型后换行,禁用 AlwaysBreakAfterReturnType: None +# 将在多行字符串前换行,禁用 AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: true +# 在模版声明后换行 +AlwaysBreakTemplateDeclarations: Yes +# 编译器属性排除,不会参与格式化 +AttributeMacros: [ '__capability', + '__output', + '__ununsed', + '[[maybe_unused]]' ] + +# 尽量将函数调用的参数放在同一行 BinPackArguments: true +# 尽量将函数声明的参数放在同一行 BinPackParameters: true +# 在位域声明的 : 前后都加空格 +BitFieldColonSpacing: Both +# 大括号换行设置 BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false + # 在 case 后换行,禁用 + AfterCaseLabel: false + # 在 class 后换行,禁用 + AfterClass: false + # 在控制语句后换行,禁用 + AfterControlStatement: Never + # 在 enum 后换行,禁用 + AfterEnum: false + # 在函数定义后换行,禁用 + AfterFunction: false + # 在 namespace 后换行,禁用 + AfterNamespace: false + # 在结构体后换行,禁用 + AfterStruct: false + # 在联合体后换行,禁用 + AfterUnion: false + # 在 extern 后换行,禁用 AfterExternBlock: false - BeforeCatch: false - BeforeElse: true - IndentBraces: false + # 在 catch 后换行,禁用 + BeforeCatch: false + # 在 else 前换行 + BeforeElse: true + # 在 lambda 后换行,禁用 + BeforeLambdaBody: false + # 在 while 前换行,禁用 + BeforeWhile: false + # 换行缩进括号,禁用 + IndentBraces: false + # 空函数的大括号换行 SplitEmptyFunction: true + # 空 class/struct/union 的大括号换行 SplitEmptyRecord: true + # 空 namespace 的大括号换行 SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None +# 在二元操作符前换行 +BreakBeforeBinaryOperators: All +# 在大括号前换行,使用自定义规则,在 BraceWrapping 中规定 BreakBeforeBraces: Custom -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeColon +# 在 concept(c++20) 前换行 +BreakBeforeConceptDeclarations: Always +# 在三元操作符前换行 BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false +# 构造函数初始化列表在冒号 : 前,逗号 , 后换行 BreakConstructorInitializers: BeforeColon -BreakAfterJavaFieldAnnotations: false +# class 继承列表在冒号 : 前,逗号 , 后换行 +BreakInheritanceList: BeforeColon +# 允许将字符串切割 BreakStringLiterals: true -ColumnLimit: 80 -CommentPragmas: '^ IWYU pragma:' +# 最大列数 +ColumnLimit: 80 +# 特殊注释的正则表达式,不会进行格式化 +CommentPragmas: '^ NO_STYLE:' +# 将多个 namespace 合并为一行,禁用 CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false +# 构造函数的初始化列表/继承列表的缩进宽度 ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true +# 续行的缩进宽度 +ContinuationIndentWidth: 2 +# 去除 C++11 的列表初始化的大括号 { 后和 } 前的空格,禁用 +Cpp11BracedListStyle: false +# 分析文件使用最多的换行符并应用到整个文件, +# 只有当无法得到结论时才会使用 UseCRLF,禁用 DeriveLineEnding: true +# 分析文件使用最多的指针/引用的对齐方式并应用到整个文件, +# 只有当无法得到结论时才会使用 PointerAlignment,禁用 DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false +# 关闭格式化,禁用 +DisableFormat: false +# 访问描述符后的空行,只保留 MaxEmptyLinesToKeep 指定的行数 +EmptyLineAfterAccessModifier: Leave +# 访问描述符前的空行,始终保留,除非是 class/struct 的开始 +EmptyLineBeforeAccessModifier: Always +# 在命名空间结束后添加注释,与 ShortNamespaceLines 共同生效 FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve +# for-each 宏,作为循环语句进行格式化 +ForEachMacros: [ 'RANGES_FOR', 'FOREACH' ] + +# if 宏,作为条件语句进行格式化 +IfMacros: [ 'IF' ] +# 将 #include 分块,规则由 IncludeCategories 指定,暂未使用 +#IncludeBlocks: Regroup +# 将 #include 分块,保留原有分块 +IncludeBlocks: Preserve +# 对 #include 进行排序,匹配了某正则表达式的 #include 拥有对应的优先级, +# 优先级越小排序越靠前,匹配不到的则默认优先级为 INT_MAX,暂未使用 IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - SortPriority: 0 - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - SortPriority: 0 - - Regex: '.*' - Priority: 1 - SortPriority: 0 -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' + # 正则 + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + # 优先级 + Priority: 2 + # 排序优先级,默认与 Priority 相同 + SortPriority: 2 + # 大小写敏感 + CaseSensitive: true + - Regex: '^((<|")(gtest|gmock|isl|json)/)' + Priority: 3 + CaseSensitive: true + - Regex: '<[[:alnum:].]+>' + Priority: 4 + CaseSensitive: true + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: true +# 判断头文件是否为相关的头文件,用于排序 +# 如 a.cpp 与 a.h,设置为 a.cpp/a_test.cpp +IncludeIsMainRegex: '(_test)?$' +# 判断头文件是否包含实现,用于排序 +IncludeIsMainSourceRegex: '(*\.hpp)$' +# 访问控制符缩进,禁用 +IndentAccessModifiers: false +# case 块缩进,禁用 +IndentCaseBlocks: false +# case 标签缩进 IndentCaseLabels: true -IndentGotoLabels: true -IndentPPDirectives: None -IndentWidth: 4 +# extern 块缩进,与 BraceWrapping.AfterExternBlock 共同生效 +IndentExternBlock: AfterExternBlock +# 缩进 goto 标签,禁用 +IndentGotoLabels: false +# 缩进预处理,在 # 后缩进 +IndentPPDirectives: AfterHash +# 缩进 requires +IndentRequiresClause: true +# 缩进宽度 +IndentWidth: 4 +# 函数返回类型换行时,缩进函数声明/函数定义的函数名,禁用 IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' +# 自动插入大括号 +InsertBraces: true +# 保留在块开始处的空行,禁用 +KeepEmptyLinesAtTheStartOfBlocks: false +# lambda 表达式函数体缩进 +LambdaBodyIndentation: OuterScope +# 语言,设置语言为 c++ +Language: Cpp + +# 开始一个块的宏的正则表达式 +MacroBlockBegin: "^MACRO_BEGIN|NS_TABLE_HEAD$" +# 结束一个块的宏的正则表达式 +MacroBlockEnd: "^MACRO_END|NS_TABLE_.*_END$" +# 最大连续空行 MaxEmptyLinesToKeep: 1 +# namespace 缩进,禁用 NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true +# namespace 宏 +NamespaceMacros: [ 'NAMESPACE' ] +# 预处理缩进,-1 表示使用默认值 IndentWidth +PPIndentWidth: -1 +# 如果构造函数的初始化列表超过一行则换行 +PackConstructorInitializers: NextLine + +# 有些情况下你会觉得怎么排版都达不到完美, +# 只能各方面妥协一下(例如你限定了行宽,但注释想放宽松点允许超一些)。 +# penalty 简单来说就是給每一次“违规”设定一个罚分, +# clang-format 帮你选择最终吃到的总罚分比较少的策略。 +# 在赋值前后换行时的罚分 +# @see https://www.zhihu.com/question/438473572/answer/1668773325 +# 在赋值前后打断的罚分 PenaltyBreakAssignment: 2 +# 在函数调用 fun( 后打断的罚分 PenaltyBreakBeforeFirstCallParameter: 19 +# 在注释中换行的罚分 PenaltyBreakComment: 300 +# 在第一个 << 点打断的罚分 PenaltyBreakFirstLessLess: 120 +# 在 ( 后打断的罚分 +PenaltyBreakOpenParenthesis: 100 +# 在字符串常量中换行的罚分 PenaltyBreakString: 1000 +# 在模版声明后打断的罚分 PenaltyBreakTemplateDeclaration: 10 +# 注释的每个字符超出 ColumnLimit 的罚分 PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Right -ReflowComments: true -SortIncludes: false +# 每个空格缩进的罚分, +# counted relative to leading non-whitespace column +PenaltyIndentedWhitespace: 0 +# 函数返回类型单独成行的罚分 +PenaltyReturnTypeOnItsOwnLine: 0 +# 指针和引用对齐,左对齐 +PointerAlignment: Left +# 修饰符对齐,由 QualifierOrder 指定 +QualifierAlignment: Custom +# 修饰符顺序 +QualifierOrder: [ 'inline', 'static', 'const', 'volatile','type' ] +# 将字符串格式化,与 ProtocolBuffers 配合使用,未使用 +RawStringFormats: + - Language: Cpp + BasedOnStyle: InheritParentConfig + Delimiters: [ pb ] +# 引用对齐,与 PointerAlignment 相同 +ReferenceAlignment: Pointer +# 重新排版注释 +ReflowComments: true +# requires 位置,单独成行 +RequiresClausePosition: OwnLine +# 在定义块之间添加空行,总是添加 +SeparateDefinitionBlocks: Always +# 设置短 namespace 长度,0 表示将所有 namespace 视为 short namespace +ShortNamespaceLines: 0 +# 排序 #include,按照字母序 +SortIncludes: CaseInsensitive +# 排序 using 声明 SortUsingDeclarations: true +# 在 C 风格类型转换后添加空格,禁用 SpaceAfterCStyleCast: false +# 在逻辑非 ! 后添加空格,禁用 SpaceAfterLogicalNot: false +# 在 template 后添加空格 SpaceAfterTemplateKeyword: true +# 在指针修饰符周围添加空格,使用 PointerAlignment +SpaceAroundPointerQualifiers: Default +# 在赋值运算符之前添加空格 SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false +# 在 case 的 : 前添加空格,禁用 +SpaceBeforeCaseColon: false +# 在 c++11 大括号初始化前添加空格 +SpaceBeforeCpp11BracedList: true +# 在构造函数初始化列表 : 前添加空格 SpaceBeforeCtorInitializerColon: true +# 在继承 : 前添加空格 SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements +# 在 ( 前添加空格,由 SpaceBeforeParensOptions 指定 +SpaceBeforeParens: Custom +# 在 ( 前添加空格的规则 +SpaceBeforeParensOptions: + # 在控制语句后添加 + AfterControlStatements: true + # 在 for-each 宏后添加,禁用 + AfterForeachMacros: false + # 在函数声明后添加,禁用 + AfterFunctionDeclarationName: false + # 在函数定义后添加,禁用 + AfterFunctionDefinitionName: false + # 在 if 宏后添加,禁用 + AfterIfMacros: false + # 在重载运算符后添加,禁用 + AfterOverloadedOperator: false + # 在 requires 后添加 + AfterRequiresInClause: true + # 在表达式中的 requires 后添加,禁用 + AfterRequiresInExpression: false + # 在非空的 () 前添加,禁用 + BeforeNonEmptyParentheses: false +# 在范围 for 循环 : 前添加空格 SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false +# 在 [ 前添加空格,禁用 +SpaceBeforeSquareBrackets: false +# 在空 {} 中添加空格 +SpaceInEmptyBlock: true +# 在空的圆括号中添加空格,禁用 SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false +# 在行后注释前添加空格(只适用于 //) +SpacesBeforeTrailingComments: 4 +# 在尖括号的 < 后和 > 前添加空格,禁用 +SpacesInAngles: Never +# 在 C 风格类型转换的括号中添加空格,禁用 +SpacesInCStyleCastParentheses: false +# 在条件判断中 ( 后 ) 前添加空格,禁用 SpacesInConditionalStatement: false +# 在容器字面量中添加空格 SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false +# 行注释前缀中的空格 +SpacesInLineCommentPrefix: + # 最大值 + Maximum: 1 + # 最小值 + Minimum: 1 +# 在 ( 后和 ) 前添加空格,禁用 SpacesInParentheses: false +# 在 [ 后和 ] 前添加空格,lamda 表达式和未指明大小的数组的声明不受影响,禁用 SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -Standard: Latest -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 8 -UseCRLF: false -UseTab: Never +# cpp 标准,使用最新支持的 +Standard: Latest +# 需要识别为宏的代码块前缀 +StatementAttributeLikeMacros: [ ] +# 需要解释为完整代码段的宏 +StatementMacros: [ ] +# tab 宽度,8 个空格 +TabWidth: 8 +# 需要识别为宏,而不是函数调用的宏 +TypenameMacros: [ ] +# 使用 \r\n 换行符,与 DeriveLineEnding 共同生效,禁用 +UseCRLF: false +# 使用 tab,禁用 +UseTab: Never +# 对空格敏感的宏 +WhitespaceSensitiveMacros: [ ] ... - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 08eb5facb..644cf33b7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: shell: bash run: | brew install x86_64-elf-gcc - brew tap riscv/riscv + brew tap riscv-software-src/riscv brew install riscv-tools - name: make build dir diff --git a/.gitignore b/.gitignore index fb7330002..6730d4eb5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,14 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # .gitinnore for Simple-XX/SimpleKernel. -bochsout.txt *.o *.gch *.tags* .DS_Store -build -cmake-build-debug -cmake-build-debug_simplekernel +build* grub-2.04.tar.xz grub-2.04 tools/opensbi @@ -20,3 +18,5 @@ iso *.bin null.d tools/aarch64-unknown-linux-gnu* +.gdbinit +tools/opensbi/build diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index f45008db4..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "tools/opensbi"] - path = tools/opensbi - url = https://github.com/riscv/opensbi.git diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/SimpleKernel.iml b/.idea/SimpleKernel.iml new file mode 100644 index 000000000..f08604bb6 --- /dev/null +++ b/.idea/SimpleKernel.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/cmake.xml b/.idea/cmake.xml new file mode 100644 index 000000000..921664e6e --- /dev/null +++ b/.idea/cmake.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 000000000..249efa28a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 000000000..79ee123c2 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/SimpleKernel_dir.xml b/.idea/dictionaries/SimpleKernel_dir.xml new file mode 100644 index 000000000..2a7f9ade7 --- /dev/null +++ b/.idea/dictionaries/SimpleKernel_dir.xml @@ -0,0 +1,16 @@ + + + + bochsrc + corei + imafdc + lriscv + opensbi + readelf + simplekernel + syms + xlen + xorriso + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..97626ba45 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml new file mode 100644 index 000000000..12ce1b3ad --- /dev/null +++ b/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..6b29ddf9f --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..79b3c9483 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..18309178f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/kernel.xml b/.idea/runConfigurations/kernel.xml new file mode 100644 index 000000000..66eb96783 --- /dev/null +++ b/.idea/runConfigurations/kernel.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/make_i386_iso.xml b/.idea/runConfigurations/make_i386_iso.xml new file mode 100644 index 000000000..d49cdd9f9 --- /dev/null +++ b/.idea/runConfigurations/make_i386_iso.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/make_x86_64_iso.xml b/.idea/runConfigurations/make_x86_64_iso.xml new file mode 100644 index 000000000..488560a44 --- /dev/null +++ b/.idea/runConfigurations/make_x86_64_iso.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/qemu_i386_debug.xml b/.idea/runConfigurations/qemu_i386_debug.xml new file mode 100644 index 000000000..aec032588 --- /dev/null +++ b/.idea/runConfigurations/qemu_i386_debug.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/qemu_riscv64_debug.xml b/.idea/runConfigurations/qemu_riscv64_debug.xml new file mode 100644 index 000000000..9ad3329d8 --- /dev/null +++ b/.idea/runConfigurations/qemu_riscv64_debug.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/qemu_x86_64_debug.xml b/.idea/runConfigurations/qemu_x86_64_debug.xml new file mode 100644 index 000000000..fcd6dcd30 --- /dev/null +++ b/.idea/runConfigurations/qemu_x86_64_debug.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/scopes/src.xml b/.idea/scopes/src.xml new file mode 100644 index 000000000..91d064d56 --- /dev/null +++ b/.idea/scopes/src.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/tool_settings.zip b/.idea/tool_settings.zip new file mode 100644 index 000000000..47ca8c075 Binary files /dev/null and b/.idea/tool_settings.zip differ diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..683e670e8 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 94577b97d..0afda3e62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,12 @@ # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). -# Based on https://github.com/SynestiaOS/SynestiaOS +# # CMakeLists.txt for Simple-XX/SimpleKernel. # CMake 入口 # 设置最小 cmake 版本 -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.13) # 跳过编译器检查 set(CMAKE_C_COMPILER_WORKS TRUE) diff --git a/cmake/toolchain_linux_aarch64.cmake b/cmake/toolchain_linux_aarch64.cmake index 5da6961f3..00c7c5885 100644 --- a/cmake/toolchain_linux_aarch64.cmake +++ b/cmake/toolchain_linux_aarch64.cmake @@ -1,5 +1,6 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # toolchain_linux_aarch64.cmake for Simple-XX/SimpleKernel. @@ -11,13 +12,13 @@ set(CMAKE_SYSTEM_PROCESSOR AARCH64) # GCC find_program(GCC aarch64-none-eabi-gcc) if (NOT GCC) - message(FATAL_ERROR "aarch64-none-eabi-gcc not found.\n" - "Run `brew install aarch64-none-eabi-gcc` to install the toolchain") + message(FATAL_ERROR "gcc-aarch64-linux-gnu not found.\n" + "Run `sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu` to install.") else () - message(STATUS "Found aarch64-none-eabi-gcc ${GCC}") + message(STATUS "Found gcc-aarch64-linux-gnu ${GCC}") endif () -set(TOOLCHAIN_PREFIX aarch64-none-eabi-) +set(TOOLCHAIN_PREFIX aarch64-linux-gnu-) set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) set(CMAKE_READELF ${TOOLCHAIN_PREFIX}readelf) @@ -31,7 +32,7 @@ set(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}ranlib) find_program(QEMU qemu-system-aarch64) if (NOT QEMU) message(FATAL_ERROR "qemu not found.\n" - "Please install qemu first.") + "Run `sudo apt-get install -y qemu-system` to install.") else () message(STATUS "Found qemu ${QEMU}") endif () diff --git a/cmake/toolchain_linux_riscv.cmake b/cmake/toolchain_linux_riscv.cmake index cca928e3c..def485301 100644 --- a/cmake/toolchain_linux_riscv.cmake +++ b/cmake/toolchain_linux_riscv.cmake @@ -1,5 +1,6 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # toolchain_linux_riscv.cmake for Simple-XX/SimpleKernel. @@ -11,7 +12,7 @@ set(CMAKE_SYSTEM_PROCESSOR RISCV) find_program(RISCV riscv64-linux-gnu-g++) if (NOT RISCV) message(FATAL_ERROR "riscv64-linux-gnu-gcc not found.\n" - "Run `sudo apt-get install -y gcc-riscv64-linux-gnu g++-riscv64-linux-gnu` to install the toolchain. Then add the bin path to you PATH.") + "Run `sudo apt-get install -y gcc-riscv64-linux-gnu g++-riscv64-linux-gnu` to install.") else () message(STATUS "Found riscv64-linux-gnu-gcc ${RISCV}.") endif () @@ -30,7 +31,7 @@ set(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}ranlib) find_program(QEMU qemu-system-riscv64) if (NOT QEMU) message(FATAL_ERROR "qemu not found.\n" - "Please install qemu-system-riscv64 first.") + "Run `sudo apt-get install -y qemu-system` to install.") else () message(STATUS "Found qemu ${QEMU}") endif () diff --git a/cmake/toolchain_linux_x86_64.cmake b/cmake/toolchain_linux_x86_64.cmake index 30f61543d..67df794bf 100644 --- a/cmake/toolchain_linux_x86_64.cmake +++ b/cmake/toolchain_linux_x86_64.cmake @@ -1,5 +1,6 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # toolchain_linux_x86_64.cmake for Simple-XX/SimpleKernel. @@ -11,7 +12,7 @@ set(CMAKE_SYSTEM_PROCESSOR x86_64) find_program(G++ g++) if (NOT G++) message(FATAL_ERROR "g++ not found.\n" - "Run `sudo apt-get install -y gcc g++` to install the toolchain") + "Run `sudo apt-get install -y gcc g++` to install.") else () message(STATUS "Found g++ ${G++}") endif () @@ -20,7 +21,7 @@ endif () find_program(XORRISO xorriso) if (NOT XORRISO) message(FATAL_ERROR "xorriso not found.\n" - "Run `sudo apt-get install -y xorriso` to install the toolchain") + "Run `sudo apt-get install -y xorriso` to install.") else () message(STATUS "Found xorriso ${XORRISO}") endif () @@ -29,25 +30,16 @@ endif () find_program(GRUB grub-file) if (NOT GRUB) message(FATAL_ERROR "grub-file not found.\n" - "Please install grub2 common first.") + "Run `sudo apt-get install -y grub2` to install.") else () message(STATUS "Found grub-file ${GRUB}") endif () -# bochs -find_program(BOCHS bochs) -if (NOT BOCHS) - message(FATAL_ERROR "bochs not found.\n" - "Please install bochs and bochs-x first.") -else () - message(STATUS "Found bochs ${BOCHS}") -endif () - # qemu find_program(QEMU qemu-system-x86_64) if (NOT QEMU) message(FATAL_ERROR "qemu not found.\n" - "Please install qemu first.") + "Run `sudo apt-get install -y qemu-system` to install.") else () message(STATUS "Found qemu ${QEMU}") endif () diff --git a/cmake/toolchain_mac_riscv.cmake b/cmake/toolchain_mac_riscv.cmake index 1b4484a36..0f054bdac 100644 --- a/cmake/toolchain_mac_riscv.cmake +++ b/cmake/toolchain_mac_riscv.cmake @@ -19,7 +19,7 @@ endif () find_program(RISCV riscv64-unknown-elf-gcc) if (NOT RISCV) message(FATAL_ERROR "riscv64-unknown-elf-gcc not found.\n" - "Run `brew tap riscv/riscv` and `brew install riscv-tools` to install the toolchain. Then add the bin path to you PATH.") + "Run `brew tap riscv-software-src/riscv` and `brew install riscv-tools` to install the toolchain. Then add the bin path to you PATH.") else () message(STATUS "Found riscv64-unknown-elf-gcc ${RISCV}.") endif () diff --git a/cmake/toolchain_mac_x86_64.cmake b/cmake/toolchain_mac_x86_64.cmake index 70faec222..b9ff72f15 100644 --- a/cmake/toolchain_mac_x86_64.cmake +++ b/cmake/toolchain_mac_x86_64.cmake @@ -52,15 +52,6 @@ else () message(STATUS "Found grub-file ${GRUB}") endif () -# bochs -find_program(BOCHS bochs) -if (NOT BOCHS) - message(FATAL_ERROR "bochs not found.\n" - "run `brew install bochs` to install the toolchain") -else () - message(STATUS "Found bochs ${BOCHS}") -endif () - # qemu find_program(QEMU qemu-system-x86_64) if (NOT QEMU) diff --git "a/docs/0_\345\267\245\345\205\267\351\223\276.md" "b/docs/0_\345\267\245\345\205\267\351\223\276.md" index 7332179b4..3e1b3ed00 100644 --- "a/docs/0_\345\267\245\345\205\267\351\223\276.md" +++ "b/docs/0_\345\267\245\345\205\267\351\223\276.md" @@ -8,38 +8,19 @@ SimpleKernel 为了保证在各个平台上的可用性,选择了较为通用 2. 内核的编译 - 使用 g++, ld 进行编译与链接 + 使用 GCC 工具链 -3. 虚拟机 +3. 模拟器 - 对于 x86/x86_64 架构,使用 bochs + 对于 x86/x86_64 架构,支持 bochs 与 qemu - 对于其它架构,使用 qemu + arm/aarch64/riscv64 架构,使用 qemu 4. 辅助脚本 - 在根目录下的 run.sh/run.py 属于此类,此外还有 tools/ 目录下的 *.sh - - - -## GCC - -GCC 需要根据目标平台与宿主机进行配置,即 target 与 host。 - -一般而言,网上有编译好的可以直接拿来用。 - -以 target=riscv64,host=osx 为例,可以在 https://github.com/riscv/homebrew-riscv 找到现成的,只需要按照说明使用 brew 安装即可。 - -对于特殊情况,可能需要自己手动编译 gcc,大致步骤如下[^1]: - -1. 安装依赖 -2. 下载源码 -3. 配置 -4. 编译 - -其中比较重要的地方是第三步,需要根据需要进行配置,你可以参考 tools/x86_64-elf-gcc.sh 的内容进行编译。 - + 主要用于环境变量管理,如 `./run.sh` 是用来编译并运行内核,`./tools/env.sh` 则规定了需要的参数。 + 此外还有模拟器配置,如 `./bochsrc_linux.txt` ## CMake @@ -47,66 +28,86 @@ CMake 可以分为两个部分 1. 主要 cmake 规则 - 所有 CMakeLists.txt 文件,规定了内核的编译方式。其中 + 所有 CMakeLists.txt 文件,规定了内核的编译方式。 - - /CMakeLists.txt + - ./CMakeLists.txt - 设置了一些 CMake 选项,并在最后通过 `add_subdirectory(${SimpleKernel_SOURCE_CODE_DIR})` 将控制权转移到 src/CMakeLists.txt + 设置了一些 CMake 选项,并在最后通过 `add_subdirectory(${SimpleKernel_SOURCE_CODE_DIR})` 将控制权转移到 ./src/CMakeLists.txt - - src/CMakeLists.txt + - ./src/CMakeLists.txt 规定了 gcc 的编译选项,指定生成的二进制文件名称,并规定生成二进制文件所需的模块 - - src/*/CMakeLists.txt + - ./src/*/CMakeLists.txt 各个模块的编译规则 2. 辅助 cmake 规则 - 用于辅助主要规则,保存在 /cmake 目录下 + 用于辅助主要规则,保存在 ./cmake 目录下 - toolchain_*.cmake 用于判断依赖是否已安装 - header_files.cmake 用于添加头文件 - - find_asm_files.cmake 用于讲汇编文件添加到编译列表 + - find_asm_files.cmake 用于将汇编文件添加到编译列表 - arch_detector.cmake 用于判断目标架构 更多细节请查看注释。 +项目地址:[CMake](https://cmake.org) +## GCC -## BOCHS +GCC 需要根据目标平台与宿主机进行配置,即 target 与 host。 -bochs 是专门用于 x86/x86_64 的虚拟机。 +一般而言,网上有编译好的可以直接拿来用。 -tools/bochsrc_*.txt 规定了虚拟机的一些选项 +以 target=riscv64,host=osx 为例,可以在 `https://github.com/riscv/homebrew-riscv` 找到现成的,只需要按照说明安装即可。 -tools/bochsinit 规定在虚拟机启动后执行的命令 +对于特殊情况,可能需要自己手动编译 gcc,大致步骤如下[^1]: -更多细节请查看注释 +1. 安装依赖 +2. 下载源码 +3. 配置 +4. 编译 +其中比较重要的地方是第三步,需要根据需要进行配置,你可以参考 ./tools/x86_64-elf-gcc.sh 的内容进行编译。 +项目地址:[GCC, the GNU Compiler Collection - GNU Project](https://gcc.gnu.org) -## QEMU +## bochs + +bochs 是专门用于 x86/x86_64 的虚拟机。 + +./tools/bochsrc_*.txt 规定了虚拟机的配置选项 + +./tools/bochsinit 规定在虚拟机启动后执行的命令 + +项目地址:[bochs: The Open Source IA-32 Emulation Project (Home Page)](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwibsOK5v5b4AhUFD0QIHTX-BS4QFnoECBMQAQ&url=https%3A%2F%2Fbochs.sourceforge.io%2F&usg=AOvVaw22vn_4SPHPDYUk_NoYgyP2) + +更多细节请查看注释 + +## qemu qemu 是支持范围更大的虚拟机,支持多种架构。 +安装: +项目地址:[QEMU](https://www.qemu.org) ## 辅助脚本 -- tools/env.sh +- ./tools/env.sh 设置目标架构,并根据设置的目标架构初始化相关变量。 更多细节请查看注释。 -- run.sh +- ./run.sh 根据 tools/env.sh 的设置在虚拟机中运行内核。 更多细节请查看注释。 - ## 相关文档 @@ -117,4 +118,3 @@ arm 工具链:https://developer.arm.com/tools-and-software/open-source-softwar riscv 工具链:https://github.com/riscv/riscv-gnu-toolchain [^1]: https://gcc.gnu.org/install/ - diff --git "a/docs/1.5_cpp\347\232\204\345\210\235\345\247\213\345\214\226.md" "b/docs/1.5_cpp\347\232\204\345\210\235\345\247\213\345\214\226.md" index e64acea6d..e5d984404 100644 --- "a/docs/1.5_cpp\347\232\204\345\210\235\345\247\213\345\214\226.md" +++ "b/docs/1.5_cpp\347\232\204\345\210\235\345\247\213\345\214\226.md" @@ -1,21 +1,19 @@ # SimpleKernel cpp 的初始化 -Simplekernel 主要是用 C++ 完成的,为了最大化 C++ 的优势,得对 C++ 的一些基础设施进行初始化。 +Simplekernel 主要是用 C++ 完成的,为了最大化 C++ 的优势,需要对 C++ 的一些基础设施进行初始化。 这一工作大致分为两部分。 ## cxxabi -cxxabi 是 C++ 特性的支持者,一些特性必须由 cxxabi 实现后才能使用。 +cxxabi 是 C++ 特性的基础,一些特性必须由 cxxabi 实现后才能使用。 -在 src/libcxx/include/cxxabi.h 与 src/libcxx/cxxabi.cpp 两个文件中定义了相关数据与函数。在链接阶段将这些定义链接上就可以正常使用相关特性了。 +在 ./src/libcxx/include/cxxabi.h 与 ./src/libcxx/cxxabi.cpp 两个文件中定义了相关数据与函数,链接阶段将这些定义链接上就可以正常使用相关特性了。 -这部分不进行深究,水太深了。 +这部分不进行深究,相关资料:[cxxabi-1.86](http://refspecs.linux-foundation.org/cxxabi-1.86.html) ## 全局对象的构造 -另一个重点是全局对象的构造。 - 在通常场景下,C++ 的全局对象会在进入 main 函数之前进行构造,在 main 返回后析构。在内核里也是一样,我们需要在进入 kernel_main 之前完成构造,不同的是我们不需要考虑析构问题,因为内核是不会返回的,当它结束的时候意味着关机了。 编译器在链接时,会将所有的全局对象的构造函数函数指针收集在一起,放在一个名为 `.init_array` 的段中,在 src/arch/*/link.ld 中,有这么一段规则: @@ -40,9 +38,9 @@ cxxabi 是 C++ 特性的支持者,一些特性必须由 cxxabi 实现后才能 } ``` -这部分规定将构造函数放在 .rodata 段里,并将这段内存用 `ctors_start` 和 `ctors_end` 两个地址进行标识,以便在代码中访问。 +这部分规定将构造函数放在 `.rodata` 段里,并将这段内存用 `ctors_start` 和 `ctors_end` 两个地址进行标识,以便在代码中访问。 -初始化由 `cpp_init` 执行,定义在 src/libcxx/src/cxxabi.cpp 中 +初始化由 `cpp_init` 执行,定义在 ./src/libcxx/src/cxxabi.cpp 中 ```c++ typedef void (*ctor_t)(void); @@ -59,12 +57,8 @@ void cpp_init(void) { 遍历这一区域的所有函数并执行,这样就完成了全局对象的构造。 - - 更多细节请查看注释。 - - ## 相关文档 https://wiki.osdev.org/C++ diff --git "a/docs/1_\347\263\273\347\273\237\345\220\257\345\212\250.md" "b/docs/1_\347\263\273\347\273\237\345\220\257\345\212\250.md" index ebfd17827..7c03a1c72 100644 --- "a/docs/1_\347\263\273\347\273\237\345\220\257\345\212\250.md" +++ "b/docs/1_\347\263\273\347\273\237\345\220\257\345\212\250.md" @@ -1,14 +1,12 @@ # SimpleKernel 启动 -内核实际上也是一个程序,它从链接脚本规定的入口点(`ENTRY(_start)`)开始执行,但在这一步之前,还得让硬件知道 `_start` 的位置,这一步骤 SImpleKernel 使用了一些开源的引导程序来辅助这一过程,你可以在 osdev 看看具体的流程[^1],这里就不再赘述。 - - +内核实际上也是一个程序,它从链接脚本规定的入口点(`ENTRY(_start)`)开始执行,但在这一步之前,还得让硬件知道 `_start` 的位置,这一步骤 SImpleKernel 使用了一些开源的引导程序来辅助这一过程,你可以在 osdev 看看具体的流程[^1],这里不再赘述。 ## IA32 -IA32 包括 i386(或 x86) 与 x86_64,它们有着相似的结构,区别在于 i386 是 32 位,而 x86_64 是 64 位。 +IA32 包括 i386(或 x86) 与 x86_64,它们在细节上有部分区别。 -SimpleKernel 使用 Grub2 进行辅助,跳过与机器打交道的部分,由 grub2 进行最最开始的设置,我们只需要处理从 `_start` 开始的代码即可。 +SimpleKernel 使用 grub2 进行辅助,跳过与机器打交道的部分,由 grub2 进行最最开始的设置,我们只需要处理从 `_start` 开始的代码即可。 相比其它架构,IA32 有太多历史包袱,这导致它的启动过程比较麻烦,尤其是实模式(16bit),保护模式(32bit),以及长模式(64bit)的切换十分复杂。幸运的是,grub2 已经帮我们进入了保护模式,这使得我们可以暂时跳过相关模式的设置。 @@ -25,7 +23,7 @@ SimpleKernel 使用 Grub2 进行辅助,跳过与机器打交道的部分,由 ```assembly // 声明这一段代码以 32 位模式编译 .code32 - + // multiboot2 文件头 // 计算头长度 .SET HEADER_LENGTH, multiboot_header_end - multiboot_header @@ -52,15 +50,15 @@ SimpleKernel 使用 Grub2 进行辅助,跳过与机器打交道的部分,由 multiboot_header_end: ``` - 只要在内核开始部分检测到符合这种布局的数据,就认为这是一个符合 multiboot2 规范的内核,引导程序会在对硬件进行初始化后将控制权交给 `_start` + 只要在内核开始部分检测到符合 multiboot2 规定的数据,就认为这是一个符合规范的内核,引导程序会在对硬件进行初始化后将控制权交给 `_start` - x86 由于 grub 已经进入了保护模式,我们不需要做什么多余的事情,在设置栈指针后直接进入 C 函数 `kernel_main` 执行即可。 - - 运行逻辑 + - 执行流 - 虚拟机-grub2-(_start)boot.S-kernel_main(kernel_main.cpp) + 模拟器 -> grub2 -> _start(boot.S ) -> kernel_main(kernel_main.cpp) - x86_64 @@ -68,8 +66,6 @@ SimpleKernel 使用 Grub2 进行辅助,跳过与机器打交道的部分,由 更多细节请查看注释。 - - ## RISCV riscv 相较 IA32 非常新,其标准至今还在更新,它没有 IA32 那么多的遗留问题与设计冗余,所以简单不少。 @@ -82,18 +78,15 @@ riscv 相较 IA32 非常新,其标准至今还在更新,它没有 IA32 那 同样,在设置栈地址后跳转到 `kernel_main` 执行。 -- 运行逻辑 +- 执行流 - 虚拟机->opensbi->_start(boot.S)->kernel_main(kernel_main.cpp) + 模拟器 -> opensbi -> _start(boot.S) -> kernel_main(kernel_main.cpp) 更多细节请查看注释。 - - ## 相关文档 [^1]: https://wiki.osdev.org/Bare_Bones [^2]: https://www.gnu.org/software/grub/manual/grub/grub.html [^3]: https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html [^4]: https://github.com/riscv/opensbi - diff --git "a/docs/2_\345\237\272\346\234\254\350\276\223\345\207\272.md" "b/docs/2_\345\237\272\346\234\254\350\276\223\345\207\272.md" index 3c62400f3..fc9a002fb 100644 --- "a/docs/2_\345\237\272\346\234\254\350\276\223\345\207\272.md" +++ "b/docs/2_\345\237\272\346\234\254\350\276\223\345\207\272.md" @@ -6,11 +6,15 @@ - 相关代码 - src/include/io.h + ./src/include/io.h - src/kernel/io.cpp + ./src/kernel/io.cpp + ./src/drv/sbi_console,riscv 架构使用下基于 opensbi 的串口输出 + ./src/drv/tui,IA32 下使用的 text user interface 输出 + + ./src/drv/uart,通用 uart 输出 ## IA32 @@ -55,11 +59,45 @@ IA32 提供了一套名为 TUI(text user interface) 的东西,它允许我们 要在屏幕上输出字符,需要向地址 0xB8000 写入数据,数据格式为 ```c++ - struct { - uint8_t c; + /** + * @brief 颜色信息 + */ + class col_t { + public: + /** + * @brief 构造一个颜色对象 + * @param _fore 前景色 + * @param _back 背景色 + */ + col_t(const COLOR::color_t _fore, const COLOR::color_t _back); + + ~col_t(void); + // 前景色 uint8_t fore : 4; + // 背景色 uint8_t back : 4; }; + + /** + * @brief 内存中的字符对象 + */ + class char_t { + public: + char_t(void); + + /** + * @brief 构造一个内存中的字符对象 + * @param _c 字符 + * @param _color 颜色 + */ + char_t(const uint8_t _c, const col_t _color); + + ~char_t(void); + // 字符 + uint8_t c; + // 颜色 + col_t color; + }; ``` 共计 2 字节大小。 @@ -80,40 +118,121 @@ IA32 提供了一套名为 TUI(text user interface) 的东西,它允许我们 - 相关代码 - src/include/color.h - - src/drv/tui/include/tui.h - - src/drv/tui/tui.cpp + ./src/include/color.h + ./src/drv/tui/include/tui.h + ./src/drv/tui/tui.cpp 更多细节请查看注释。 - - ## RISCV -riscv 通过 UART 进行输出,但我们并不需要自己写 UART 驱动,opensbi 提供了线程的接口,直接调用即可。 +riscv 通过 uart 进行输出,但我们并不需要自己写 uart 驱动,opensbi 提供了现成的接口,直接调用即可。 + +```c++ +void OPENSBI::put_char(const char _c) { + ecall(_c, 0, 0, 0, 0, 0, FID_CONSOLE_PUTCHAR, EID_CONSOLE_PUTCHAR); + return; +} +``` + +- 颜色设置 + + 由于实际使用的是串口,所以可以通过控制字符来实现对颜色的控制 + ```c++ + void SBI_CONSOLE::set_color(const COLOR::color_t _color) const { + // 根据 _color 构造字符串 + char *tmp = nullptr; + switch (_color) { + case COLOR::BLACK: { + tmp = (char *)"\033[30m"; + break; + } + case COLOR::RED: { + tmp = (char *)"\033[31m"; + break; + } + case COLOR::GREEN: { + tmp = (char *)"\033[32m"; + break; + } + case COLOR::YELLOW: { + tmp = (char *)"\033[33m"; + break; + } + case COLOR::BLUE: { + tmp = (char *)"\033[34m"; + break; + } + case COLOR::PURPLE: { + tmp = (char *)"\033[35m"; + break; + } + case COLOR::CYAN: { + tmp = (char *)"\033[36m"; + break; + } + case COLOR::WHITE: { + tmp = (char *)"\033[37m"; + break; + } + case COLOR::GREY: { + tmp = (char *)"\033[90m"; + break; + } + case COLOR::LIGHT_RED: { + tmp = (char *)"\033[91m"; + break; + } + case COLOR::LIGHT_GREEN: { + tmp = (char *)"\033[92m"; + break; + } + case COLOR::LIGHT_YELLOW: { + tmp = (char *)"\033[93m"; + break; + } + case COLOR::LIGHT_BLUE: { + tmp = (char *)"\033[94m"; + break; + } + case COLOR::LIGHT_PURPLE: { + tmp = (char *)"\033[95m"; + break; + } + case COLOR::LIGHT_CYAN: { + tmp = (char *)"\033[96m"; + break; + } + case COLOR::LIGHT_WHITE: { + tmp = (char *)"\033[97m"; + break; + } + } + // 写入 + write_string(tmp); + color = _color; + return; + } + ``` + +opensbi 接口文档:[riscv-sbi-doc](https://github.com/riscv-non-isa/riscv-sbi-doc/blob/master/riscv-sbi.adoc) - 相关代码 - src/include/color.h - - src/drv/opensbi/include/opensbi.h + ./src/include/color.h - src/drv/opensbi/opensbi.cpp + ./src/drv/opensbi/include/opensbi.h - src/drv/sbi_console/include/sbi_console.h - - src/drv/sbi_console/sbi_console.cpp + ./src/drv/opensbi/opensbi.cpp + ./src/drv/sbi_console/include/sbi_console.h + ./src/drv/sbi_console/sbi_console.cpp 更多细节请查看注释。 - - ## 相关文档 opensbi:https://github.com/riscv/opensbi diff --git "a/docs/3_\350\247\243\346\236\220\345\220\257\345\212\250\344\277\241\346\201\257.md" "b/docs/3_\350\247\243\346\236\220\345\220\257\345\212\250\344\277\241\346\201\257.md" index fe4202ea2..e5a9d2bd4 100644 --- "a/docs/3_\350\247\243\346\236\220\345\220\257\345\212\250\344\277\241\346\201\257.md" +++ "b/docs/3_\350\247\243\346\236\220\345\220\257\345\212\250\344\277\241\346\201\257.md" @@ -6,56 +6,222 @@ - 相关代码 - src/include/boot_info.h - - src/include/resource.h - + ./src/include/boot_info.h + ./src/include/resource.h ## IA32 在启动时我们使用了 grub2+multiboot2 的方式进行引导,在同时还会为我们提供所需要的硬件信息。 -grub2 会通过 eax 和 ebx 两个寄存器将信息传递给我们,只需要在启动阶段保存它们,就能在后面进行解析,获取硬件信息。 +grub2 会通过 `eax` 和 `ebx` 两个寄存器将信息传递给我们,只需要在启动阶段保存它们,就能在后面进行解析,获取硬件信息。 multiboot2 使用迭代方法寻找所需信息,函数 `multiboot2_iter(bool (*_fun)(const iter_data_t *, void *), void *_data)` 提供了这一接口。 - 相关代码 - src/arch/ia32/i386/boot/boot.S - - src/drv/multiboot2/include/multiboot2.h - - src/drv/multiboot2/multiboot2.cpp + ./src/arch/ia32/i386/boot/boot.S + ./src/drv/multiboot2/include/multiboot2.h + ./src/drv/multiboot2/multiboot2.cpp 更多细节请查看注释。 - - ## RISCV -opensbi 会将 dtb 信息的地址传递给内核,原理与 multiboot2 相似,但能够提供更为丰富的信息,相应的,dtb 的解析也更为复杂。 - -`void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), void * _data)` 函数提供了迭代功能。 +设备树(device tree)是嵌入式设备常用的硬件配置信息传递方式,在启动时,opensbi 会将设备树信息的地址传递给内核, + +```assembly +.section .init +.globl _start +.type _start, @function +.extern kernel_main +.extern cpp_init +.extern boot_info_addr +.extern dtb_init_hart +_start: + // 保存 sbi 传递的参数 + // 将 a0 的值传递给 dtb_init_hart + sw a0, dtb_init_hart, t0 + // 将 a1 的值传递给 boot_info_addr + sw a1, boot_info_addr, t0 + // 设置栈地址 + la sp, stack_top + // 初始化 C++ + call cpp_init + // 跳转到 C 代码执行 + call kernel_main +``` + +内核会在 `BOOT_INFO` 中进行初始化,解析其内容。 + +```c++ +namespace BOOT_INFO { +bool init(void) { + auto res = DTB::get_instance().dtb_init(); + if (inited == false) { + inited = true; + info("BOOT_INFO init.\n"); + } + else { + info("BOOT_INFO reinit.\n"); + } + return res; +} +}; // namespace BOOT_INFO + +bool DTB::dtb_init(void) { + // 头信息 + dtb_info.header = (fdt_header_t *)BOOT_INFO::boot_info_addr; + // 魔数 + assert(be32toh(dtb_info.header->magic) == FDT_MAGIC); + // 版本 + assert(be32toh(dtb_info.header->version) == FDT_VERSION); + // 设置大小 + BOOT_INFO::boot_info_size = be32toh(dtb_info.header->totalsize); + // 内存保留区 + dtb_info.reserved = + (fdt_reserve_entry_t *)(BOOT_INFO::boot_info_addr + + be32toh(dtb_info.header->off_mem_rsvmap)); + // 数据区 + dtb_info.data = + BOOT_INFO::boot_info_addr + be32toh(dtb_info.header->off_dt_struct); + // 字符区 + dtb_info.str = + BOOT_INFO::boot_info_addr + be32toh(dtb_info.header->off_dt_strings); + // 检查保留内存 + dtb_mem_reserved(); + // 初始化 map + bzero(nodes, sizeof(nodes)); + bzero(phandle_map, sizeof(phandle_map)); + // 初始化节点的基本信息 + dtb_iter(DT_ITER_BEGIN_NODE | DT_ITER_END_NODE | DT_ITER_PROP, dtb_init_cb, + nullptr); + // 中断信息初始化,因为需要查找 phandle,所以在基本信息初始化完成后进行 + dtb_iter(DT_ITER_PROP, dtb_init_interrupt_cb, nullptr); +// #define DEBUG +#ifdef DEBUG + // 输出所有信息 + for (size_t i = 0; i < nodes[0].count; i++) { + std::cout << nodes[i].path << ": " << std::endl; + for (size_t j = 0; j < nodes[i].prop_count; j++) { + printf("%s: ", nodes[i].props[j].name); + for (size_t k = 0; k < nodes[i].props[j].len / 4; k++) { + printf("0x%X ", + be32toh(((uint32_t *)nodes[i].props[j].addr)[k])); + } + printf("\n"); + } + } +#undef DEBUG +#endif + return true; +} +``` + +`void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), void * _data)` 是解析的核心函数 + +```c++ +void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), + void *_data, uintptr_t _addr) { + // 迭代变量 + iter_data_t iter; + // 路径深度 + iter.path.len = 0; + // 数据地址 + iter.addr = (uint32_t *)_addr; + // 节点索引 + iter.nodes_idx = 0; + // 开始 flag + bool begin = true; + + while (1) { + // + iter.type = be32toh(iter.addr[0]); + switch (iter.type) { + case FDT_NOP: { + // 跳过 type + iter.addr++; + break; + } + case FDT_BEGIN_NODE: { + // 第 len 深底的名称 + iter.path.path[iter.path.len] = (char *)(iter.addr + 1); + // 深度+1 + iter.path.len++; + iter.nodes_idx = begin ? 0 : (iter.nodes_idx + 1); + begin = false; + if (_cb_flags & DT_ITER_BEGIN_NODE) { + if (_cb(&iter, _data)) { + return; + } + } + // 跳过 type + iter.addr++; + // 跳过 name + iter.addr += + COMMON::ALIGN(strlen((char *)iter.addr) + 1, 4) / 4; + break; + } + case FDT_END_NODE: { + if (_cb_flags & DT_ITER_END_NODE) { + if (_cb(&iter, _data)) { + return; + } + } + // 这一级结束了,所以 -1 + iter.path.len--; + // 跳过 type + iter.addr++; + break; + } + case FDT_PROP: { + iter.prop_len = be32toh(iter.addr[1]); + iter.prop_name = (char *)(dtb_info.str + be32toh(iter.addr[2])); + iter.prop_addr = iter.addr + 3; + if (_cb_flags & DT_ITER_PROP) { + if (_cb(&iter, _data)) { + return; + } + } + iter.prop_name = nullptr; + iter.prop_addr = nullptr; + // 跳过 type + iter.addr++; + // 跳过 len + iter.addr++; + // 跳过 nameoff + iter.addr++; + // 跳过 data,并进行对齐 + iter.addr += COMMON::ALIGN(iter.prop_len, 4) / 4; + iter.prop_len = 0; + break; + } + case FDT_END: { + return; + } + default: { + printf("unrecognized token 0x%X\n", iter.type); + return; + } + } + } + return; +} +``` - 相关代码 - src/arch/riscv64/boot/boot.S - - src/drv/dtb/include/dtb.h - - src/drv/dtb/dtb.cpp - + ./src/arch/riscv64/boot/boot.S + ./src/drv/dtb/include/dtb.h + ./src/drv/dtb/dtb.cpp 更多细节请查看注释。 - - ## 相关文档 multiboot2 规范:https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html diff --git "a/docs/4_\347\211\251\347\220\206\345\206\205\345\255\230\347\256\241\347\220\206.md" "b/docs/4_\347\211\251\347\220\206\345\206\205\345\255\230\347\256\241\347\220\206.md" index e2bc62d4e..6bd19127f 100644 --- "a/docs/4_\347\211\251\347\220\206\345\206\205\345\255\230\347\256\241\347\220\206.md" +++ "b/docs/4_\347\211\251\347\220\206\345\206\205\345\255\230\347\256\241\347\220\206.md" @@ -4,81 +4,143 @@ 分配器的基类是 `ALLOCATOR` 类,这是一个抽象类,必须被继承后才能使用。 -由抽象类派生出的具体类是一个分配算法,使用了首次匹配算法。 +由抽象类派生出的具体类是一个分配算法,使用了首次匹配算法(First Fit)。 分配器以 4KB 为最小管理单位,每次分配或回收都是它的整数倍。 此外,为了区分内核权限的内存和用户权限的内存,在 PMM 类的实现中有两个指向 FIRSTFIT 类的 ALLOCATOR 类指针,这允许我们指定要操作的内存位置。 +```c++ +/** + * @brief 内存分配器抽象类 + */ +class ALLOCATOR { +private: +protected: + /// 分配器名称 + const char *name; + /// 当前管理的内存区域地址 + uintptr_t allocator_start_addr; + /// 当前管理的内存区域长度 + size_t allocator_length; + /// 当前管理的内存区域空闲长度 + size_t allocator_free_count; + /// 当前管理的内存区域已使用长度 + size_t allocator_used_count; + +public: + /** + * @brief 构造内存分配器 + * @param _name 分配器名 + * @param _addr 要管理的内存开始地址 + * @param _len 要管理的内存长度,单位以具体实现为准 + */ + ALLOCATOR(const char *_name, uintptr_t _addr, size_t _len); + + virtual ~ALLOCATOR(void) = 0; + + /** + * @brief 分配 _len 页 + * @param _len 页数 + * @return uintptr_t 分配到的地址 + */ + virtual uintptr_t alloc(size_t _len) = 0; + + /** + * @brief 在指定地址分配 _len 长度 + * @param _addr 指定的地址 + * @param _len 长度 + * @return true 成功 + * @return false 失败 + */ + virtual bool alloc(uintptr_t _addr, size_t _len) = 0; + + /** + * @brief 释放 _len 长度 + * @param _addr 地址 + * @param _len 长度 + */ + virtual void free(uintptr_t _addr, size_t _len) = 0; + + /** + * @brief 已使用数量 + * @return size_t 数量 + */ + virtual size_t get_used_count(void) const = 0; + + /** + * @brief 空闲数量 + * @return size_t 数量 + */ + virtual size_t get_free_count(void) const = 0; +}; +``` + +具体到不同架构,物理内存管理会从 `BOOT_INFO` 获取信息进行初始化 + +```c++ +bool PMM::init(void) { + // 获取物理内存信息 + resource_t mem_info = BOOT_INFO::get_memory(); + // 设置物理地址的起点与长度 + start = mem_info.mem.addr; + length = mem_info.mem.len; + // 计算页数 + total_pages = length / COMMON::PAGE_SIZE; + // 内核空间地址开始 + kernel_space_start = COMMON::KERNEL_START_ADDR; + // 长度手动指定 + kernel_space_length = COMMON::KERNEL_SPACE_SIZE; + // 非内核空间在内核空间结束后 + non_kernel_space_start = + COMMON::KERNEL_START_ADDR + COMMON::KERNEL_SPACE_SIZE; + // 长度为总长度减去内核长度 + non_kernel_space_length = length - kernel_space_length; + + // 创建分配器 + // 内核空间 + static FIRSTFIT first_fit_allocator_kernel( + "First Fit Allocator(kernel space)", kernel_space_start, + kernel_space_length / COMMON::PAGE_SIZE); + kernel_space_allocator = (ALLOCATOR *)&first_fit_allocator_kernel; + // 非内核空间 + static FIRSTFIT first_fit_allocator( + "First Fit Allocator", non_kernel_space_start, + non_kernel_space_length / COMMON::PAGE_SIZE); + allocator = (ALLOCATOR *)&first_fit_allocator; + + // 内核实际占用页数 这里也算了 0~1M 的 reserved 内存 + size_t kernel_pages = + (COMMON::ALIGN(COMMON::KERNEL_END_ADDR, COMMON::PAGE_SIZE) - + COMMON::ALIGN(COMMON::KERNEL_START_ADDR, COMMON::PAGE_SIZE)) / + COMMON::PAGE_SIZE; + // 将内核已使用部分划分出来 + if (alloc_pages_kernel(COMMON::KERNEL_START_ADDR, kernel_pages) == true) { + // 将 multiboot2/dtb 信息移动到内核空间 + move_boot_info(); + info("pmm init.\n"); + return true; + } + else { + assert(0); + return false; + } +} +``` + - 相关代码 - src/include/mem/allocator.h + ./src/include/mem/allocator.h - src/include/mem/firstfit.h + ./src/include/mem/firstfit.h - src/include/mem/pmm.h + ./src/include/mem/pmm.h - src/kernel/allocator.cpp + ./src/kernel/allocator.cpp - src/kernel/firstfit.cpp + ./src/kernel/firstfit.cpp - src/kernel/pmm.cpp - - - -## IA32 - - - - -- 相关代码 - - src/arch/ia32/i386/boot/boot.S - - src/drv/multiboot2/include/multiboot2.h - - src/drv/multiboot2/multiboot2.cpp - + ./src/kernel/pmm.cpp 更多细节请查看注释。 - - - -## RISCV - -opensbi 会将 dtb 信息的地址传递给内核,原理与 multiboot2 相似,但能够提供更为丰富的信息,相应的,dtb 的解析也更为复杂。 - -`void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), void * _data)` 函数提供了迭代功能。 - -- 相关代码 - - src/arch/riscv64/boot/boot.S - - src/drv/dtb/include/dtb.h - - src/drv/dtb/dtb.cpp - - - - -更多细节请查看注释。 - - - -## 相关文档 - -multiboot2 规范:https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html - -opensbi:https://github.com/riscv/opensbi - -device-tree:https://github.com/devicetree-org/devicetree-specification - -dtb解析0: https://e-mailky.github.io/2016-12-06-dts-introduce - -dtb解析1: https://e-mailky.github.io/2019-01-14-dts-1 - -dtb解析2: https://e-mailky.github.io/2019-01-14-dts-2 - -dtb解析3: https://e-mailky.github.io/2019-01-14-dts-3 - diff --git "a/docs/5_\350\231\232\346\213\237\345\206\205\345\255\230\347\256\241\347\220\206.md" "b/docs/5_\350\231\232\346\213\237\345\206\205\345\255\230\347\256\241\347\220\206.md" new file mode 100644 index 000000000..d175c8feb --- /dev/null +++ "b/docs/5_\350\231\232\346\213\237\345\206\205\345\255\230\347\256\241\347\220\206.md" @@ -0,0 +1,170 @@ +# SimpleKernel 虚拟内存管理 + +虚拟内存与架构密切相关,但仍然能够找到它们的共同之处。 + +在 `cpu.hpp` 中封装了它们的差异,使得可以获得一个近似一致的虚拟内存管理逻辑。 + + +## IA32 + +TODO + +## RISCV + +页表结构可以抽象为以下数据 + +```c++ +namespace CPU { +/** + * @brief pte 结构 + * @todo 使用 pte 结构重写 vmm + */ +struct pte_t { + enum { + VALID_OFFSET = 0, + READ_OFFSET = 1, + WRITE_OFFSET = 2, + EXEC_OFFSET = 3, + USER_OFFSET = 4, + GLOBAL_OFFSET = 5, + ACCESSED_OFFSET = 6, + DIRTY_OFFSET = 7, + VALID = 1 << VALID_OFFSET, + READ = 1 << READ_OFFSET, + WRITE = 1 << WRITE_OFFSET, + EXEC = 1 << EXEC_OFFSET, + USER = 1 << USER_OFFSET, + GLOBAL = 1 << GLOBAL_OFFSET, + ACCESSED = 1 << ACCESSED_OFFSET, + DIRTY = 1 << DIRTY_OFFSET, + }; + union { + struct { + uint64_t flags : 8; + uint64_t rsw : 2; + uint64_t ppn : 44; + uint64_t reserved : 10; + }; + uint64_t val; + }; + + pte_t(void) { + val = 0; + return; + } + pte_t(uint64_t _val) : val(_val) { + return; + } + friend std::ostream &operator<<(std::ostream &_os, const pte_t &_pte) { + printf("val: 0x%p, valid: %s, read: %s, write: %s, exec: %s, user: %s, " + "global: %s, accessed: %s, dirty: %s, rsw: 0x%p, ppn: 0x%p", + _pte.val, (_pte.flags & VALID) == VALID ? "true" : "false", + (_pte.flags & READ) == READ ? "true" : "false", + (_pte.flags & WRITE) == WRITE ? "true" : "false", + (_pte.flags & EXEC) == EXEC ? "true" : "false", + (_pte.flags & USER) == USER ? "true" : "false", + (_pte.flags & GLOBAL) == GLOBAL ? "true" : "false", + (_pte.flags & ACCESSED) == ACCESSED ? "true" : "false", + (_pte.flags & DIRTY) == DIRTY ? "true" : "false", _pte.rsw, + _pte.ppn); + return _os; + } +}; + +/** + * @brief satp 结构 + */ +struct satp_t { + enum { + NONE = 0, + SV39 = 8, + SV48 = 9, + SV57 = 10, + SV64 = 11, + }; + static constexpr const char *MODE_NAME[] = { + [NONE] = "NONE", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", + [SV39] = "SV39", [SV48] = "SV48", [SV57] = "SV57", [SV64] = "SV64", + }; + + union { + struct { + uint64_t ppn : 44; + uint64_t asid : 16; + uint64_t mode : 4; + }; + uint64_t val; + }; + + static constexpr const uint64_t PPN_OFFSET = 12; + + satp_t(void) { + val = 0; + return; + } + satp_t(uint64_t _val) : val(_val) { + return; + } + friend std::ostream &operator<<(std::ostream &_os, const satp_t &_satp) { + printf("val: 0x%p, ppn: 0x%p, asid: 0x%p, mode: %s", _satp.val, + _satp.ppn, _satp.asid, MODE_NAME[_satp.mode]); + return _os; + } +}; +}; // namespace CPU +``` + +以下是在执行 mmap 映射内存时的逻辑。 +```c++ +// 在 _pgd 中查找 _va 对应的页表项 +// 如果未找到,_alloc 为真时会进行分配 +pte_t *VMM::find(const pt_t _pgd, uintptr_t _va, bool _alloc) { + pt_t pgd = _pgd; + // sv39 共有三级页表,一级一级查找 + // -1 是因为最后一级是具体的某一页,在函数最后直接返回 + for (size_t level = VMM_PT_LEVEL - 1; level > 0; level--) { + // 每次循环会找到 _va 的第 level 级页表 pgd + // 相当于 pgd_level[VPN_level],这样相当于得到了第 level 级页表的地址 + pte_t *pte = (pte_t *)&pgd[PX(level, _va)]; + // 解引用 pte,如果有效,获取 level+1 级页表, + if ((*pte & VMM_PAGE_VALID) == 1) { + // pgd 指向下一级页表 + // *pte 保存的是页表项,需要转换为对应的物理地址 + pgd = (pt_t)PTE2PA(*pte); + } + // 如果无效 + else { + // 判断是否需要分配 + // 如果需要 + if (_alloc == true) { + // 申请新的物理页 + pgd = (pt_t)PMM::get_instance().alloc_page_kernel(); + bzero(pgd, COMMON::PAGE_SIZE); + // 申请失败则返回 + if (pgd == nullptr) { + // 如果出现这种情况,说明物理内存不够,一般不会出现 + assert(0); + return nullptr; + } + // 清零 + bzero(pgd, COMMON::PAGE_SIZE); + // 填充页表项 + *pte = PA2PTE((uintptr_t)pgd) | VMM_PAGE_VALID; + } + // 不分配的话直接返回 + else { + return nullptr; + } + } + } + // 0 最低级 pt + return &pgd[PX(0, _va)]; +} +``` + +更多细节请查看注释。 + +## 相关文档 + +TODO \ No newline at end of file diff --git "a/docs/6_\345\240\206\347\256\241\347\220\206.md" "b/docs/6_\345\240\206\347\256\241\347\220\206.md" new file mode 100644 index 000000000..cf8777280 --- /dev/null +++ "b/docs/6_\345\240\206\347\256\241\347\220\206.md" @@ -0,0 +1,59 @@ +# SimpleKernel 堆管理 + +堆(heap)是内核使用动态内存的主要方式,`HEAP` 同样继承了 `ALLOCATOR`,这里使用了 slab 分配算法。 + + +堆的初始化,将内存分为内核/用户两部分 +```c++ +bool HEAP::init(void) { + // 内核空间 + static SLAB slab_allocator_kernel( + "SLAB Allocator Kernel", PMM::get_instance().get_kernel_space_start(), + PMM::get_instance().get_kernel_space_length() * COMMON::PAGE_SIZE, + true); + allocator_kernel = (ALLOCATOR *)&slab_allocator_kernel; + // 非内核空间 + static SLAB slab_allocator_non_kernel( + "SLAB Allocator", PMM::get_instance().get_non_kernel_space_start(), + PMM::get_instance().get_non_kernel_space_length() * COMMON::PAGE_SIZE, + false); + allocator_non_kernel = (ALLOCATOR *)&slab_allocator_non_kernel; + info("heap init.\n"); + return 0; +} +``` + +在堆管理实现后,动态内存就可以使用了,这允许我们用更多的语言特性。 + +`malloc` 与 `free` 的实现 +```c++ +/** + * @brief malloc 定义 + * @param _size 要申请的 bytes + * @return void* 申请到的地址 + */ +extern "C" void *malloc(size_t _size) { + return (void *)HEAP::get_instance().malloc(_size); +} + +/** + * @brief free 定义 + * @param _p 要释放的内存地址 + */ +extern "C" void free(void *_p) { + HEAP::get_instance().free(_p); + return; +} +``` + +slab 部分较复杂,可以直接参考代码。 + +- 相关代码 + + ./src/include/mem/heap.h + + ./src/kernel/heap.cpp + + ./src/include/mem/slab.h + + ./src/kernel/slab.cpp diff --git "a/docs/7_c++stl\347\232\204\346\224\257\346\214\201.md" "b/docs/7_c++stl\347\232\204\346\224\257\346\214\201.md" new file mode 100644 index 000000000..2ba67e27f --- /dev/null +++ "b/docs/7_c++stl\347\232\204\346\224\257\346\214\201.md" @@ -0,0 +1,7 @@ +# SimpleKernel c++ stl 的支持 + +C++ 的标准模版库(STL) 非常强大,这里我们只使用了部分,使用了 [Alinshans/MyTinySTL](https://github.com/Alinshans/MyTinySTL) 的实现。 + +- 相关代码 + + ./src/libcxx/include/* diff --git "a/docs/8_\344\270\255\346\226\255.md" "b/docs/8_\344\270\255\346\226\255.md" new file mode 100644 index 000000000..737054e09 --- /dev/null +++ "b/docs/8_\344\270\255\346\226\255.md" @@ -0,0 +1,595 @@ +# SimpleKernel 中断 + +## IA32 + +TODO + +## RISCV + +寄存结构及中断上下文 +```c++ +namespace CPU { +/// 机器模式定义 +enum { + U_MODE = 0, + S_MODE = 1, + M_MODE = 3, +}; + +enum { + INTR_SOFT = 0, + /// U 态软中断 + INTR_SOFT_U = INTR_SOFT + U_MODE, + /// S 态软中断 + INTR_SOFT_S = INTR_SOFT + S_MODE, + /// M 态软中断 + INTR_SOFT_M = INTR_SOFT + M_MODE, + INTR_TIMER = 4, + /// U 态时钟中断 + INTR_TIMER_U = INTR_TIMER + U_MODE, + /// S 态时钟中断 + INTR_TIMER_S = INTR_TIMER + S_MODE, + /// M 态时钟中断 + INTR_TIMER_M = INTR_TIMER + M_MODE, + INTR_EXTERN = 8, + /// U 态外部中断 + INTR_EXTERN_U = INTR_EXTERN + U_MODE, + /// S 态外部中断 + INTR_EXTERN_S = INTR_EXTERN + S_MODE, + /// M 态外部中断 + INTR_EXTERN_M = INTR_EXTERN + M_MODE, +}; + +enum { + EXCP_INSTRUCTION_ADDRESS_MISALIGNED = 0, + EXCP_INSTRUCTION_ACCESS_FAULT = 1, + EXCP_ILLEGAL_INSTRUCTION = 2, + EXCP_BREAKPOINT = 3, + EXCP_LOAD_ADDRESS_MISALIGNED = 4, + EXCP_LOAD_ACCESS_FAULT = 5, + EXCP_STORE_AMO_ADDRESS_MISALIGNED = 6, + EXCP_STORE_AMO_ACCESS_FAULT = 7, + EXCP_ECALL = 8, + EXCP_ECALL_U = EXCP_ECALL + U_MODE, + EXCP_ECALL_S = EXCP_ECALL + S_MODE, + EXCP_ECALL_M = EXCP_ECALL + M_MODE, + EXCP_INSTRUCTION_PAGE_FAULT = 12, + EXCP_LOAD_PAGE_FAULT = 13, + EXCP_STORE_AMO_PAGE_FAULT = 15, +}; + +// Supervisor Status Register, sstatus +// User Interrupt Enable +static constexpr const uint64_t SSTATUS_UIE = 1 << 0; +// Supervisor Interrupt Enable +static constexpr const uint64_t SSTATUS_SIE = 1 << 1; +// User Previous Interrupt Enable +static constexpr const uint64_t SSTATUS_UPIE = 1 << 4; +// Supervisor Previous Interrupt Enable +static constexpr const uint64_t SSTATUS_SPIE = 1 << 5; +// Previous mode, 1=Supervisor, 0=User +static constexpr const uint64_t SSTATUS_SPP = 1 << 8; + +/** + * @brief sstatus 寄存器定义 + */ +struct sstatus_t { + union { + struct { + // Reserved Writes Preserve Values, Reads Ignore Values (WPRI) + uint64_t wpri1 : 1; + // interrupt enable + uint64_t sie : 1; + uint64_t wpri12 : 3; + // previous interrupt enable + uint64_t spie : 1; + uint64_t ube : 1; + uint64_t wpri3 : 1; + // previous mode (supervisor) + uint64_t spp : 1; + uint64_t wpri4 : 4; + // FPU status + uint64_t fs : 2; + // extensions status + uint64_t xs : 2; + uint64_t wpri5 : 1; + // permit supervisor user memory access + uint64_t sum : 1; + // make executable readable + uint64_t mxr : 1; + uint64_t wpri6 : 12; + // U-mode XLEN + uint64_t uxl : 2; + uint64_t wpri7 : 29; + // status dirty + uint64_t sd : 1; + }; + uint64_t val; + }; + + sstatus_t(void) { + val = 0; + return; + } + sstatus_t(uint64_t _val) : val(_val) { + return; + } + friend std::ostream &operator<<(std::ostream &_os, + const sstatus_t &_sstatus) { + printf("val: 0x%p, sie: %s, spie: %s, spp: %s", _sstatus.val, + (_sstatus.sie == true ? "enable" : "disable"), + (_sstatus.spie == true ? "enable" : "disable"), + (_sstatus.spp == true ? "S mode" : "U mode")); + return _os; + } +}; + +// Supervisor Interrupt Enable +// software +static constexpr const uint64_t SIE_SSIE = 1 << 1; +// timer +static constexpr const uint64_t SIE_STIE = 1 << 5; +// external +static constexpr const uint64_t SIE_SEIE = 1 << 9; + +/// 中断模式 直接 +static constexpr const uint64_t TVEC_DIRECT = 0xFFFFFFFFFFFFFFFC; +/// 中断模式 向量 +static constexpr const uint64_t TVEC_VECTORED = 0xFFFFFFFFFFFFFFFD; + +/** + * @brief 允许中断 + */ +static inline void ENABLE_INTR(void) { + WRITE_SSTATUS(READ_SSTATUS().val | SSTATUS_SIE); + return; +} + +/** + * @brief 允许中断 + * @param _sstatus 要设置的 sstatus + */ +static inline void ENABLE_INTR(sstatus_t &_sstatus) { + _sstatus.sie = true; + return; +} + +/** + * @brief 禁止中断 + */ +static inline void DISABLE_INTR(void) { + WRITE_SSTATUS(READ_SSTATUS().val & ~SSTATUS_SIE); + return; +} + +/** + * @brief 禁止中断 + * @param _sstatus 要设置的原 sstatus 值 + */ +static inline void DISABLE_INTR(sstatus_t &_sstatus) { + _sstatus.sie = false; + return; +} + +/** + * @brief 读取中断状态 + * @return true 允许 + * @return false 禁止 + */ +static inline bool STATUS_INTR(void) { + sstatus_t x = READ_SSTATUS(); + return x.sie; +} + +/** + * @brief 通用寄存器 + */ +struct xregs_t { + uintptr_t zero; + uintptr_t ra; + uintptr_t sp; + uintptr_t gp; + uintptr_t tp; + uintptr_t t0; + uintptr_t t1; + uintptr_t t2; + uintptr_t s0; + uintptr_t s1; + uintptr_t a0; + uintptr_t a1; + uintptr_t a2; + uintptr_t a3; + uintptr_t a4; + uintptr_t a5; + uintptr_t a6; + uintptr_t a7; + uintptr_t s2; + uintptr_t s3; + uintptr_t s4; + uintptr_t s5; + uintptr_t s6; + uintptr_t s7; + uintptr_t s8; + uintptr_t s9; + uintptr_t s10; + uintptr_t s11; + uintptr_t t3; + uintptr_t t4; + uintptr_t t5; + uintptr_t t6; +}; + +/** + * @brief 浮点寄存器 + */ +struct fregs_t { + uintptr_t ft0; + uintptr_t ft1; + uintptr_t ft2; + uintptr_t ft3; + uintptr_t ft4; + uintptr_t ft5; + uintptr_t ft6; + uintptr_t ft7; + uintptr_t fs0; + uintptr_t fs1; + uintptr_t fa0; + uintptr_t fa1; + uintptr_t fa2; + uintptr_t fa3; + uintptr_t fa4; + uintptr_t fa5; + uintptr_t fa6; + uintptr_t fa7; + uintptr_t fs2; + uintptr_t fs3; + uintptr_t fs4; + uintptr_t fs5; + uintptr_t fs6; + uintptr_t fs7; + uintptr_t fs8; + uintptr_t fs9; + uintptr_t fs10; + uintptr_t fs11; + uintptr_t ft8; + uintptr_t ft9; + uintptr_t ft10; + uintptr_t ft11; +}; + +/** + * @brief 所有寄存器,在中断时使用,共 32+32+7=71 个 + */ +struct all_regs_t { + xregs_t xregs; + fregs_t fregs; + uintptr_t sepc; + uintptr_t stval; + uintptr_t scause; + uintptr_t sie; + sstatus_t sstatus; + satp_t satp; + uintptr_t sscratch; +}; + +}; // namespace CPU +``` + +现场保存与恢复 + +```assembly + +// 寄存器长度,8 字节 +.equ REG_BYTES, 8 +// 所有寄存器数量 +.equ ALL_REGS, 71 +// 保存所有寄存器需要的大小 +.equ ALL_SIZE, (ALL_REGS * REG_BYTES) + +// 将寄存器 a 保存在 c 偏移 b 的位置 +.macro sd_base a, b, c +sd \a, ((\b) * REG_BYTES)(\c) +.endm + +// 从 c 的偏移 b 处获取数据并赋值给寄存器 a +.macro ld_base a, b, c +ld \a, ((\b) * REG_BYTES)(\c) +.endm + +// 将 float 寄存器 a 保存在 c 偏移 b 的位置 +.macro fsd_base a, b, c +fsd \a, ((\b) * REG_BYTES)(\c) +.endm + +// 从 c 的偏移 b 处获取数据并赋值给 float 寄存器 a +.macro fld_base a, b, c +fld \a, ((\b) * REG_BYTES)(\c) +.endm + +/** + * @brief 保存所有寄存器 + * @param _base 要保存到的基地址 + */ +.macro all_regs_save _base + sd_base zero, 0, \_base + sd_base ra, 1, \_base + sd_base sp, 2, \_base + sd_base gp, 3, \_base + sd_base tp, 4, \_base + sd_base t0, 5, \_base + sd_base t1, 6, \_base + sd_base t2, 7, \_base + sd_base s0, 8, \_base + sd_base s1, 9, \_base + sd_base a0, 10, \_base + sd_base a1, 11, \_base + sd_base a2, 12, \_base + sd_base a3, 13, \_base + sd_base a4, 14, \_base + sd_base a5, 15, \_base + sd_base a6, 16, \_base + sd_base a7, 17, \_base + sd_base s2, 18, \_base + sd_base s3, 19, \_base + sd_base s4, 20, \_base + sd_base s5, 21, \_base + sd_base s6, 22, \_base + sd_base s7, 23, \_base + sd_base s8, 24, \_base + sd_base s9, 25, \_base + sd_base s10, 26, \_base + sd_base s11, 27, \_base + sd_base t3, 28, \_base + sd_base t4, 29, \_base + sd_base t5, 30, \_base + sd_base t6, 31, \_base + + fsd_base ft0, 32, \_base + fsd_base ft1, 33, \_base + fsd_base ft2, 34, \_base + fsd_base ft3, 35, \_base + fsd_base ft4, 36, \_base + fsd_base ft5, 37, \_base + fsd_base ft6, 38, \_base + fsd_base ft7, 39, \_base + fsd_base fs0, 40, \_base + fsd_base fs1, 41, \_base + fsd_base fa0, 42, \_base + fsd_base fa1, 43, \_base + fsd_base fa2, 44, \_base + fsd_base fa3, 45, \_base + fsd_base fa4, 46, \_base + fsd_base fa5, 47, \_base + fsd_base fa6, 48, \_base + fsd_base fa7, 49, \_base + fsd_base fs2, 50, \_base + fsd_base fs3, 51, \_base + fsd_base fs4, 52, \_base + fsd_base fs5, 53, \_base + fsd_base fs6, 54, \_base + fsd_base fs7, 55, \_base + fsd_base fs8, 56, \_base + fsd_base fs9, 57, \_base + fsd_base fs10, 58, \_base + fsd_base fs11, 59, \_base + fsd_base ft8, 60, \_base + fsd_base ft9, 61, \_base + fsd_base ft10, 62, \_base + fsd_base ft11, 63, \_base + + csrr t0, sepc + sd_base t0, 64, \_base + csrr t0, stval + sd_base t0, 65, \_base + csrr t0, scause + sd_base t0, 66, \_base + csrr t0, sie + sd_base t0, 67, \_base + csrr t0, sstatus + sd_base t0, 68, \_base + csrr t0, satp + sd_base t0, 69, \_base + csrr t0, sscratch + sd_base t0, 70, \_base +.endm + +/** + * @brief 恢复所有寄存器 + * @param _base 要恢复数据的基地址 + */ +.macro all_regs_load _base + ld_base t0, 64, \_base + csrw sepc, t0 + ld_base t0, 65, \_base + csrw stval, t0 + ld_base t0, 66, \_base + csrw scause, t0 + ld_base t0, 67, \_base + csrw sie, t0 + ld_base t0, 68, \_base + csrw sstatus, t0 + ld_base t0, 69, \_base + csrw satp, t0 + ld_base t0, 70, \_base + csrw sscratch, t0 + + ld_base zero, 0, \_base + ld_base ra, 1, \_base + ld_base sp, 2, \_base + ld_base gp, 3, \_base + ld_base tp, 4, \_base + ld_base t0, 5, \_base + ld_base t1, 6, \_base + ld_base t2, 7, \_base + ld_base s0, 8, \_base + ld_base s1, 9, \_base + ld_base a0, 10, \_base + ld_base a1, 11, \_base + ld_base a2, 12, \_base + ld_base a3, 13, \_base + ld_base a4, 14, \_base + ld_base a5, 15, \_base + ld_base a6, 16, \_base + ld_base a7, 17, \_base + ld_base s2, 18, \_base + ld_base s3, 19, \_base + ld_base s4, 20, \_base + ld_base s5, 21, \_base + ld_base s6, 22, \_base + ld_base s7, 23, \_base + ld_base s8, 24, \_base + ld_base s9, 25, \_base + ld_base s10, 26, \_base + ld_base s11, 27, \_base + ld_base t3, 28, \_base + ld_base t4, 29, \_base + ld_base t5, 30, \_base + ld_base t6, 31, \_base + + fld_base ft0, 32, \_base + fld_base ft1, 33, \_base + fld_base ft2, 34, \_base + fld_base ft3, 35, \_base + fld_base ft4, 36, \_base + fld_base ft5, 37, \_base + fld_base ft6, 38, \_base + fld_base ft7, 39, \_base + fld_base fs0, 40, \_base + fld_base fs1, 41, \_base + fld_base fa0, 42, \_base + fld_base fa1, 43, \_base + fld_base fa2, 44, \_base + fld_base fa3, 45, \_base + fld_base fa4, 46, \_base + fld_base fa5, 47, \_base + fld_base fa6, 48, \_base + fld_base fa7, 49, \_base + fld_base fs2, 50, \_base + fld_base fs3, 51, \_base + fld_base fs4, 52, \_base + fld_base fs5, 53, \_base + fld_base fs6, 54, \_base + fld_base fs7, 55, \_base + fld_base fs8, 56, \_base + fld_base fs9, 57, \_base + fld_base fs10, 58, \_base + fld_base fs11, 59, \_base + fld_base ft8, 60, \_base + fld_base ft9, 61, \_base + fld_base ft10, 62, \_base + fld_base ft11, 63, \_base +.endm + +.section .text +// 保存所有寄存器 +.globl trap_entry +.extern trap_handler +.align 4 +trap_entry: + // 将所有寄存器保存到栈上 + // 在栈上留出保存寄存器的空间 + addi sp, sp, -ALL_SIZE + all_regs_save sp + + // 调用 intr.cpp: trap_handler + // 传递参数 + csrr a0, sepc + csrr a1, stval + csrr a2, scause + mv a3, sp + csrr a4, sie + csrr a5, sstatus + csrr a6, satp + csrr a7, sscratch + jal trap_handler + + // 从栈上恢复所有寄存器 + all_regs_load sp + // 释放栈上用于保存寄存器的空间 + addi sp, sp, ALL_SIZE + + // 跳转到 sepc 处执行 + sret +``` + +中断初始化 +```c++ +int32_t INTR::init(void) { + // 设置 trap vector + CPU::WRITE_STVEC((uintptr_t)trap_entry); + // 直接跳转到处理函数 + CPU::STVEC_DIRECT(); + // 设置处理函数 + for (auto &i : interrupt_handlers) { + i = handler_default; + } + for (auto &i : excp_handlers) { + i = handler_default; + } + // 内部中断初始化 + CLINT::get_instance().init(); + // 外部中断初始化 + PLIC::get_instance().init(); + // 注册缺页中断 + register_excp_handler(CPU::EXCP_LOAD_PAGE_FAULT, pg_load_excp); + // 注册缺页中断 + register_excp_handler(CPU::EXCP_STORE_AMO_PAGE_FAULT, pg_store_excp); + info("intr init.\n"); + return 0; +} +``` + +中断处理 +```c++ +/** + * @brief 中断处理函数 + * @param _scause 原因 + * @param _sepc 值 + * @param _stval 值 + * @param _scause 值 + * @param _all_regs 保存在栈上的所有寄存器,实际上是 sp + * @param _sie 值 + * @param _sstatus 值 + * @param _sscratch 值 + */ +extern "C" void trap_handler(uintptr_t _sepc, uintptr_t _stval, + uintptr_t _scause, CPU::all_regs_t *_all_regs, + uintptr_t _sie, CPU::sstatus_t _sstatus, + CPU::satp_t _satp, uintptr_t _sscratch) { + if (_scause & CPU::CAUSE_INTR_MASK) { +// 中断 + // 跳转到对应的处理函数 + INTR::get_instance().do_interrupt(_scause & CPU::CAUSE_CODE_MASK, 0, + nullptr); + } + else { +// 异常 +// 跳转到对应的处理函数 + INTR::get_instance().do_excp(_scause & CPU::CAUSE_CODE_MASK, 0, + nullptr); + } + return; +} +``` + +更多细节请查看注释。 + +- 相关代码 + + ./src/arch/riscv64/context.S + + ./src/arch/riscv64/intr/intr_s.S + + ./src/arch/riscv64/intr/include/intr.h + + ./src/arch/riscv64/intr/intr.cpp + + ./src/arch/riscv64/intr/clint.cpp + + ./src/arch/riscv64/intr/plic.cpp + + ./src/arch/riscv64/intr/timer.cpp + +## 相关文档 + +TODO diff --git a/docs/UEFI_Spec_2_10_Aug29.pdf b/docs/UEFI_Spec_2_10_Aug29.pdf new file mode 100644 index 000000000..b56b7b993 Binary files /dev/null and b/docs/UEFI_Spec_2_10_Aug29.pdf differ diff --git a/run.py b/run.py deleted file mode 100644 index b19a84e8b..000000000 --- a/run.py +++ /dev/null @@ -1,75 +0,0 @@ - -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). -# -# run.py for Simple-XX/SimpleKernel. - -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import os -import argparse -import subprocess - -# 通用依赖 -# cmake, make -# i386/x86_64 需要的依赖 -# bochs, grub2, x86_64-elf-g++ -# arm 需要的依赖 -# qemu-system-aarch64, arm-none-eabi-g++ -# riscv64 需要的依赖 -# qemu-system-riscv64, riscv64-unknown-elf-g++ -# Depends = ["cmake", "make"] - -# 仅运行,默认所有依赖都可用 - - -# 清空旧目录 -def clean(): - proc = subprocess.call( - "rm -rf ./build/*", shell=True) - proc = subprocess.call( - "mkdir -p ./build/", shell=True) - return - - -# 执行 CMake -def cmake(arch): - if arch == "riscv" or arch == "riscv64": - proc = subprocess.call( - ["cd ./build && cmake -DCMAKE_TOOLCHAIN_FILE=./cmake/toolchain_mac_riscv.cmake -DARCH=riscv64 -DCMAKE_BUILD_TYPE=DEBUG .."], shell=True) - return - - -def run(arch, simulator): - if arch == "riscv" or arch == "riscv64": - proc = subprocess.call( - "qemu-system-riscv64 -machine virt -serial stdio -bios ./tools/opensbi/build/platform/generic/firmware/fw_jump.elf -kernel ./build/bin/kernel.elf", shell=True) - return - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "-v", "--version", help="Print version.", action='version', version='dev') - # 目标平台 - parser.add_argument("-a", "--arch", required=False, default="i386", type=str, - help="i386, x86_64, arm, aarch64, riscv64") - # 虚拟机 - parser.add_argument("-s", "--simulator", required=False, default="bochs", type=str, - help="bochs, qemu") - args = parser.parse_args() - # i386/x86_64 暂不支持 qemu 模拟 - if (args.arch == "i386" or args.arch == "x86_64") and args.simulator == "qemu": - print("Not Support yet.") - exit(1) - clean() - cmake(args.arch) - # 执行 make - proc = subprocess.call( - ["cd ./build && make"], shell=True) - run(args.arch, args.simulator) - return - - -if __name__ == '__main__': - main() diff --git a/run.sh b/run.sh index 930714d6e..c3f397fcc 100644 --- a/run.sh +++ b/run.sh @@ -1,23 +1,23 @@ +#!/bin/bash -# This file is a part of Simple-XX/SimpleKernel +# This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # # run.sh for Simple-XX/SimpleKernel. # 在虚拟机中运行内核 -#!/bin/bash # shell 执行出错时终止运行 set -e # 输出实际执行内容 -# set -x +#set -x source ./tools/env.sh export PATH="${GRUB_PATH}:$PATH" # 重新编译 -mkdir -p ./build/ -rm -rf ./build/* -cd ./build +mkdir -p ./build_${ARCH}/ +rm -rf ./build_${ARCH}/* +cd ./build_${ARCH} cmake -DCMAKE_TOOLCHAIN_FILE=./cmake/${TOOLS} -DARCH=${ARCH} -DCMAKE_BUILD_TYPE=DEBUG .. make cd ../ @@ -37,12 +37,14 @@ if [ ${ARCH} == "riscv64" ]; then # OPENSBI 不存在则编译 if [ ! -f ${OPENSBI} ]; then echo build opensbi. - git submodule init - git submodule update cd ./tools/opensbi mkdir -p build export CROSS_COMPILE=${TOOLCHAIN_PREFIX} - make PLATFORM=generic FW_JUMP_ADDR=0x80200000 + export FW_JUMP=y + export FW_JUMP_ADDR=0x80200000 + export PLATFORM_RISCV_XLEN=64 + export PLATFORM=generic + make cd ../.. echo build opensbi done. fi @@ -56,31 +58,37 @@ else rm -rf -f ${iso_boot}/* fi +# 初始化 gdb +if [ ${DEBUG} == 1 ]; then + cp ./tools/gdbinit ./.gdbinit + echo "" >> ./.gdbinit + echo "file "${kernel} >> ./.gdbinit + if [ ${ARCH} == "riscv64" ]; then + echo "add-symbol-file "${OPENSBI} >> ./.gdbinit + fi + echo "target remote localhost:1234" >> ./.gdbinit + GDB_OPT='-S -gdb tcp::1234' + echo "Run gdb-multiarch in another shell" +fi + # 设置 grub 相关数据 if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then + mkdir -p ${iso_boot_grub} cp ${kernel} ${iso_boot} - mkdir ${iso_boot_grub} - touch ${iso_boot_grub}/grub.cfg - echo 'set timeout=15 - set default=0 - menuentry "SimpleKernel" { - multiboot2 /boot/kernel.elf "KERNEL_ELF" - }' >${iso_boot_grub}/grub.cfg + cp ./tools/grub.cfg ${iso_boot_grub}/ fi # 运行虚拟机 if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then - if [ ${IA32_USE_QEMU} == 0 ]; then - ${GRUB_PATH}/grub-mkrescue -o ${iso} ${iso_folder} - bochs -q -f ${bochsrc} -rc ./tools/bochsinit - else - qemu-system-x86_64 -cdrom ${iso} -m 128M \ - -monitor telnet::2333,server,nowait -serial stdio - fi + qemu-system-x86_64 -cdrom ${iso} -m 128M \ + -monitor telnet::2333,server,nowait -serial stdio \ + ${GDB_OPT} elif [ ${ARCH} == "aarch64" ]; then qemu-system-aarch64 -machine virt -cpu cortex-a72 -kernel ${kernel} \ - -monitor telnet::2333,server,nowait -serial stdio -nographic + -monitor telnet::2333,server,nowait -serial stdio -nographic \ + ${GDB_OPT} elif [ ${ARCH} == "riscv64" ]; then qemu-system-riscv64 -machine virt -bios ${OPENSBI} -kernel ${kernel} \ - -monitor telnet::2333,server,nowait -serial stdio -nographic + -monitor telnet::2333,server,nowait -serial stdio -nographic \ + ${GDB_OPT} fi diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 65862d877..04256df16 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). -# Based on https://github.com/SynestiaOS/SynestiaOS +# # CMakeLists.txt for Simple-XX/SimpleKernel. # 设置编译规则 @@ -36,9 +36,14 @@ else () set(CMAKE_BUILD_TYPE DEBUG) endif () +# 代码优化级别 +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") +set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}") + # 通用选项 -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffreestanding -nostdlib -nostdinc -fexceptions -nostartfiles -fPIC -no-pie -O2 -Wall -Wextra -MMD") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffreestanding -nostdlib -nostdinc -fexceptions -nostartfiles -fPIC -no-pie -O2 -Wall -Wextra -MMD") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffreestanding -nostdlib -nostdinc -fexceptions -nostartfiles -fPIC -no-pie -Wall -Wextra -MMD") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffreestanding -nostdlib -nostdinc -fexceptions -nostartfiles -fPIC -no-pie -Wall -Wextra -MMD") set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}") # 输出相关信息 @@ -58,11 +63,11 @@ add_subdirectory(${SimpleKernel_SOURCE_CODE_DIR}/libcxx) # 将各个子对象链接为内核文件 add_executable(${KernelName} - $ - $ - $ - $ - $) + $ + $ + $ + $ + $) # 指定链接脚本 target_link_options(${KernelName} PRIVATE -T ${SimpleKernel_SOURCE_CODE_DIR}/arch/${SimpleKernelArch}/link.ld) @@ -80,23 +85,40 @@ elseif (SimpleKernelArch STREQUAL riscv64) target_link_options(${KernelName} PRIVATE -Wl,-melf64lriscv) endif () -# readelf -a +# objcopy --only-keep-debug foo foo.dbg 创建一个包含调试信息的文件 add_custom_command(TARGET ${KernelName} - POST_BUILD - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMAND ${CMAKE_READELF} -a ${KernelName} >> ${KernelName}.readelf_a || (exit 0) - COMMENT "readelf -a") + POST_BUILD + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_OBJCOPY} --only-keep-debug ${KernelName} ${KernelName}.debug + COMMENT "Generating kernel debug...") -# objdump -D +# objcopy --strip-debug foo 创建一个去掉调试信息的( strip 的)可执行文件 +# objcopy --add-gnu-debuglink=foo.dbg foo 为 strip 的文件添加调试信息链接 +add_custom_command(TARGET ${KernelName} + POST_BUILD + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_OBJCOPY} --strip-debug ${KernelName} + COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink=${KernelName}.debug ${KernelName} + COMMENT "Generating raw kernel...") + +# nm add_custom_command(TARGET ${KernelName} - POST_BUILD - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMAND ${CMAKE_OBJDUMP} -D ${KernelName} >> ${KernelName}.disassembly - COMMENT "Disassembling...") + POST_BUILD + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_NM} -a -A -C -l -n -s --special-syms --synthetic ${KernelName} + > ${KernelName}.nm + COMMENT "nm...") -# objdump -t +# readelf -a +add_custom_command(TARGET ${KernelName} + POST_BUILD + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_READELF} -a ${KernelName} > ${KernelName}.readelf || (exit 0) + COMMENT "readelf...") + +# objdump -D add_custom_command(TARGET ${KernelName} - POST_BUILD - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMAND ${CMAKE_OBJDUMP} -t ${KernelName} >> ${KernelName}.symtlb - COMMENT "Generating symbol table...") + POST_BUILD + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_OBJDUMP} -D ${KernelName} > ${KernelName}.disassembly + COMMENT "Disassembling...") diff --git a/src/arch/CMakeLists.txt b/src/arch/CMakeLists.txt index 4d1137946..e17ec2700 100644 --- a/src/arch/CMakeLists.txt +++ b/src/arch/CMakeLists.txt @@ -9,6 +9,6 @@ if (SimpleKernelArch STREQUAL "ia32/i386" OR SimpleKernelArch STREQUAL "ia32/x86_64") add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ia32) else () -# 其它情况跳转到与 SimpleKernelArch 同名目录即可 + # 其它情况跳转到与 SimpleKernelArch 同名目录即可 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${SimpleKernelArch}) endif () diff --git a/src/arch/aarch64/CMakeLists.txt b/src/arch/aarch64/CMakeLists.txt index 867f4091c..8cac90b45 100644 --- a/src/arch/aarch64/CMakeLists.txt +++ b/src/arch/aarch64/CMakeLists.txt @@ -1,5 +1,6 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # CMakeLists.txt for Simple-XX/SimpleKernel. diff --git a/src/arch/aarch64/boot/boot.S b/src/arch/aarch64/boot/boot.S index 7d88fbad4..2504a4de0 100644 --- a/src/arch/aarch64/boot/boot.S +++ b/src/arch/aarch64/boot/boot.S @@ -4,6 +4,8 @@ // Based on https://wiki.osdev.org/Raspberry_Pi_Bare_Bones // boot.S for Simple-XX/SimpleKernel. +// clang-format off + .section .init // Entry point for the kernel. @@ -12,7 +14,7 @@ // r1 -> 0x00000C42 - machine id // r2 -> 0x00000100 - start of ATAGS // preserve these registers as argument for kernel_main -.globl _start +.global _start .type _start, @function .extern kernel_main // 规定起始地址 diff --git a/src/arch/aarch64/hardware.h b/src/arch/aarch64/hardware.h index 9ea08afbd..5a66f7338 100644 --- a/src/arch/aarch64/hardware.h +++ b/src/arch/aarch64/hardware.h @@ -1,87 +1,96 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// hardware.h for Simple-XX/SimpleKernel. +/** + * @file hardware.h + * @brief 硬件定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _HARDWARE_H_ -#define _HARDWARE_H_ +#ifndef SIMPLEKERNEL_HARDWARE_H +#define SIMPLEKERNEL_HARDWARE_H -#include "stdint.h" +#include "cstdint" namespace HARDWARE { - // for raspi2 & 3 - static constexpr const uint32_t MMIO_BASE = 0x3F000000; - // The offsets for reach register. - static constexpr const uint32_t GPIO_BASE = MMIO_BASE + 0x200000; - // Controls actuation of pull up/down to ALL GPIO pins. - static constexpr const uint32_t GPPUD = GPIO_BASE + 0x94; - // Controls actuation of pull up/down for specific GPIO pin. - static constexpr const uint32_t GPPUDCLK0 = GPIO_BASE + 0x98; +// for raspi2 & 3 +static constexpr const uint32_t MMIO_BASE = 0x3F000000; +// The offsets for reach register. +static constexpr const uint32_t GPIO_BASE = MMIO_BASE + 0x200000; +// Controls actuation of pull up/down to ALL GPIO pins. +static constexpr const uint32_t GPPUD = GPIO_BASE + 0x94; +// Controls actuation of pull up/down for specific GPIO pin. +static constexpr const uint32_t GPPUDCLK0 = GPIO_BASE + 0x98; - // 设备 id - static constexpr const uint32_t DEVICE_ID_SD_CARD = 0x00000000; - static constexpr const uint32_t DEVICE_ID_UART0 = 0x00000001; - static constexpr const uint32_t DEVICE_ID_UART1 = 0x00000002; - static constexpr const uint32_t DEVICE_ID_USB_HCD = 0x00000003; - static constexpr const uint32_t DEVICE_ID_I2C0 = 0x00000004; - static constexpr const uint32_t DEVICE_ID_I2C1 = 0x00000005; - static constexpr const uint32_t DEVICE_ID_I2C2 = 0x00000006; - static constexpr const uint32_t DEVICE_ID_SPI = 0x00000007; - static constexpr const uint32_t DEVICE_ID_CCP2TX = 0x00000008; +// 设备 id +static constexpr const uint32_t DEVICE_ID_SD_CARD = 0x00000000; +static constexpr const uint32_t DEVICE_ID_UART0 = 0x00000001; +static constexpr const uint32_t DEVICE_ID_UART1 = 0x00000002; +static constexpr const uint32_t DEVICE_ID_USB_HCD = 0x00000003; +static constexpr const uint32_t DEVICE_ID_I2C0 = 0x00000004; +static constexpr const uint32_t DEVICE_ID_I2C1 = 0x00000005; +static constexpr const uint32_t DEVICE_ID_I2C2 = 0x00000006; +static constexpr const uint32_t DEVICE_ID_SPI = 0x00000007; +static constexpr const uint32_t DEVICE_ID_CCP2TX = 0x00000008; - // 时钟 id - static constexpr const uint32_t CLOCK_ID_RESERVED = 0x000000000; - static constexpr const uint32_t CLOCK_ID_EMMC = 0x000000001; - static constexpr const uint32_t CLOCK_ID_UART = 0x000000002; - static constexpr const uint32_t CLOCK_ID_ARM = 0x000000003; - static constexpr const uint32_t CLOCK_ID_CORE = 0x000000004; - static constexpr const uint32_t CLOCK_ID_V3D = 0x000000005; - static constexpr const uint32_t CLOCK_ID_H264 = 0x000000006; - static constexpr const uint32_t CLOCK_ID_ISP = 0x000000007; - static constexpr const uint32_t CLOCK_ID_SDRAM = 0x000000008; - static constexpr const uint32_t CLOCK_ID_PIXEL = 0x000000009; - static constexpr const uint32_t CLOCK_ID_PWM = 0x00000000a; - static constexpr const uint32_t CLOCK_ID_HEVC = 0x00000000b; - static constexpr const uint32_t CLOCK_ID_EMMC2 = 0x00000000c; - static constexpr const uint32_t CLOCK_ID_M2MC = 0x00000000d; - static constexpr const uint32_t CLOCK_ID_PIXEL_BVB = 0x00000000e; +// 时钟 id +static constexpr const uint32_t CLOCK_ID_RESERVED = 0x000000000; +static constexpr const uint32_t CLOCK_ID_EMMC = 0x000000001; +static constexpr const uint32_t CLOCK_ID_UART = 0x000000002; +static constexpr const uint32_t CLOCK_ID_ARM = 0x000000003; +static constexpr const uint32_t CLOCK_ID_CORE = 0x000000004; +static constexpr const uint32_t CLOCK_ID_V3D = 0x000000005; +static constexpr const uint32_t CLOCK_ID_H264 = 0x000000006; +static constexpr const uint32_t CLOCK_ID_ISP = 0x000000007; +static constexpr const uint32_t CLOCK_ID_SDRAM = 0x000000008; +static constexpr const uint32_t CLOCK_ID_PIXEL = 0x000000009; +static constexpr const uint32_t CLOCK_ID_PWM = 0x00000000a; +static constexpr const uint32_t CLOCK_ID_HEVC = 0x00000000b; +static constexpr const uint32_t CLOCK_ID_EMMC2 = 0x00000000c; +static constexpr const uint32_t CLOCK_ID_M2MC = 0x00000000d; +static constexpr const uint32_t CLOCK_ID_PIXEL_BVB = 0x00000000e; - // 电压 id - static constexpr const uint32_t VOLTAGE_ID_RESERVED = 0x000000000; - static constexpr const uint32_t VOLTAGE_ID_CORE = 0x000000001; - static constexpr const uint32_t VOLTAGE_ID_SDRAM_C = 0x000000002; - static constexpr const uint32_t VOLTAGE_ID_SDRAM_P = 0x000000003; - static constexpr const uint32_t VOLTAGE_ID_SDRAM_I = 0x000000004; +// 电压 id +static constexpr const uint32_t VOLTAGE_ID_RESERVED = 0x000000000; +static constexpr const uint32_t VOLTAGE_ID_CORE = 0x000000001; +static constexpr const uint32_t VOLTAGE_ID_SDRAM_C = 0x000000002; +static constexpr const uint32_t VOLTAGE_ID_SDRAM_P = 0x000000003; +static constexpr const uint32_t VOLTAGE_ID_SDRAM_I = 0x000000004; - // mailbox 地址 - static constexpr const uint32_t MAILBOX_OFFSET = 0x0000B880; - static constexpr const uint32_t MAILBOX_READ_OFFSET = 0x0; - static constexpr const uint32_t MAILBOX_POLL_OFFSET = 0x10; - static constexpr const uint32_t MAILBOX_SENDER_OFFSET = 0x14; - static constexpr const uint32_t MAILBOX_STATUS_OFFSET = 0x18; - static constexpr const uint32_t MAILBOX_CONFIG_OFFSET = 0x1C; - static constexpr const uint32_t MAILBOX_WRITE_OFFSET = 0x20; - static constexpr const uint32_t MAILBOX_VIDEOCORE = - MMIO_BASE + MAILBOX_OFFSET; - static constexpr const uint32_t MAILBOX_READ = - MAILBOX_VIDEOCORE + MAILBOX_READ_OFFSET; - static constexpr const uint32_t MAILBOX_POLL = - MAILBOX_VIDEOCORE + MAILBOX_POLL_OFFSET; - static constexpr const uint32_t MAILBOX_SENDER = - MAILBOX_VIDEOCORE + MAILBOX_SENDER_OFFSET; - static constexpr const uint32_t MAILBOX_STATUS = - MAILBOX_VIDEOCORE + MAILBOX_STATUS_OFFSET; - static constexpr const uint32_t MAILBOX_CONFIG = - MAILBOX_VIDEOCORE + MAILBOX_CONFIG_OFFSET; - static constexpr const uint32_t MAILBOX_WRITE = - MAILBOX_VIDEOCORE + MAILBOX_WRITE_OFFSET; - static constexpr const uint32_t MAILBOX_RESPONSE_SUCCESSFUL = 0x80000000; - static constexpr const uint32_t MAILBOX_RESPONSE_ERROR = 0x80000001; - // 1<<31 - static constexpr const uint32_t MAILBOX_FULL = 0x80000000; - // 1<<30 - static constexpr const uint32_t MAILBOX_EMPTY = 0x40000000; -}; +// mailbox 地址 +static constexpr const uint32_t MAILBOX_OFFSET = 0x0000B880; +static constexpr const uint32_t MAILBOX_READ_OFFSET = 0x0; +static constexpr const uint32_t MAILBOX_POLL_OFFSET = 0x10; +static constexpr const uint32_t MAILBOX_SENDER_OFFSET = 0x14; +static constexpr const uint32_t MAILBOX_STATUS_OFFSET = 0x18; +static constexpr const uint32_t MAILBOX_CONFIG_OFFSET = 0x1C; +static constexpr const uint32_t MAILBOX_WRITE_OFFSET = 0x20; +static constexpr const uint32_t MAILBOX_VIDEOCORE = MMIO_BASE + MAILBOX_OFFSET; +static constexpr const uint32_t MAILBOX_READ + = MAILBOX_VIDEOCORE + MAILBOX_READ_OFFSET; +static constexpr const uint32_t MAILBOX_POLL + = MAILBOX_VIDEOCORE + MAILBOX_POLL_OFFSET; +static constexpr const uint32_t MAILBOX_SENDER + = MAILBOX_VIDEOCORE + MAILBOX_SENDER_OFFSET; +static constexpr const uint32_t MAILBOX_STATUS + = MAILBOX_VIDEOCORE + MAILBOX_STATUS_OFFSET; +static constexpr const uint32_t MAILBOX_CONFIG + = MAILBOX_VIDEOCORE + MAILBOX_CONFIG_OFFSET; +static constexpr const uint32_t MAILBOX_WRITE + = MAILBOX_VIDEOCORE + MAILBOX_WRITE_OFFSET; +static constexpr const uint32_t MAILBOX_RESPONSE_SUCCESSFUL = 0x80000000; +static constexpr const uint32_t MAILBOX_RESPONSE_ERROR = 0x80000001; +// 1<<31 +static constexpr const uint32_t MAILBOX_FULL = 0x80000000; +// 1<<30 +static constexpr const uint32_t MAILBOX_EMPTY = 0x40000000; +}; // namespace HARDWARE -#endif /* _HARDWARE_H_ */ +#endif /* SIMPLEKERNEL_HARDWARE_H */ diff --git a/src/arch/aarch64/link.ld b/src/arch/aarch64/link.ld index cbceed022..98c8d306a 100644 --- a/src/arch/aarch64/link.ld +++ b/src/arch/aarch64/link.ld @@ -1,7 +1,10 @@ -/* This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +/* This file is a part of Simple-XX/SimpleKernel + * (https://github.com/Simple-XX/SimpleKernel). * - * link.ld for Simple-XX/SimpleKernel. */ + * link.ld for Simple-XX/SimpleKernel. + * 链接脚本,指定生成的二进制文件的布局 + */ OUTPUT_FORMAT(elf64-littleaarch64) diff --git a/src/arch/aarch64/port/include/port.h b/src/arch/aarch64/port/include/port.h index 37310d170..bd644de17 100644 --- a/src/arch/aarch64/port/include/port.h +++ b/src/arch/aarch64/port/include/port.h @@ -1,27 +1,37 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// port.h for Simple-XX/SimpleKernel. +/** + * @file port.h + * @brief arm 端口驱动 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _PORT_H_ -#define _PORT_H_ +#ifndef SIMPLEKERNEL_PORT_H +#define SIMPLEKERNEL_PORT_H -#include "stdint.h" +#include "cstdint" namespace PORT { - // 端口读一个字节 - uint8_t inb(const uint32_t port); - // 端口读一个字 - uint16_t inw(const uint32_t port); - // 端口读一个双字 - uint32_t ind(const uint32_t port); - // 端口写一个字节 - void outb(const uint32_t port, const uint8_t data); - // 端口写一个字 - void outw(const uint32_t port, const uint16_t data); - // 端口写一个双字 - void outd(const uint32_t port, const uint32_t data); -}; +// 端口读一个字节 +uint8_t inb(const uint32_t port); +// 端口读一个字 +uint16_t inw(const uint32_t port); +// 端口读一个双字 +uint32_t ind(const uint32_t port); +// 端口写一个字节 +void outb(const uint32_t port, const uint8_t data); +// 端口写一个字 +void outw(const uint32_t port, const uint16_t data); +// 端口写一个双字 +void outd(const uint32_t port, const uint32_t data); +}; // namespace PORT -#endif /* _PORT_H_ */ +#endif /* SIMPLEKERNEL_PORT_H */ diff --git a/src/arch/aarch64/port/port.cpp b/src/arch/aarch64/port/port.cpp index 8a24cf5a8..a52701cf6 100644 --- a/src/arch/aarch64/port/port.cpp +++ b/src/arch/aarch64/port/port.cpp @@ -1,8 +1,18 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// port.cpp for Simple-XX/SimpleKernel. +/** + * @file port.cpp + * @brief 串口驱动 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ #include "port.h" @@ -15,7 +25,7 @@ uint16_t PORT::inw(const uint32_t port __attribute((unused))) { } uint32_t PORT::ind(const uint32_t port) { - return *(volatile uint32_t *)port; + return *(volatile uint32_t*)port; } void PORT::outw(const uint32_t port __attribute((unused)), @@ -29,6 +39,6 @@ void PORT::outb(const uint32_t port __attribute((unused)), } void PORT::outd(const uint32_t port, const uint32_t data) { - *(volatile uint32_t *)port = data; + *(volatile uint32_t*)port = data; return; } diff --git a/src/arch/ia32/CMakeLists.txt b/src/arch/ia32/CMakeLists.txt index 50b05bb34..49e2c1707 100644 --- a/src/arch/ia32/CMakeLists.txt +++ b/src/arch/ia32/CMakeLists.txt @@ -22,10 +22,9 @@ if (${SimpleKernelArch} STREQUAL "ia32/i386") find_asm_source_files(intr_asm_src ${arch_SOURCE_DIR}/i386/intr) aux_source_directory(${arch_SOURCE_DIR}/i386/intr intr_cpp_src) - set(intr_src ${intr_asm_src} ${intr_cpp_src}) + set(intr_src ${intr_asm_src} ${intr_cpp_src}) - -# 64 位 + # 64 位 elseif (${SimpleKernelArch} STREQUAL "ia32/x86_64") # 寻找汇编文件 find_asm_source_files(boot_asm_src ${arch_SOURCE_DIR}/x86_64/boot) @@ -38,7 +37,7 @@ elseif (${SimpleKernelArch} STREQUAL "ia32/x86_64") find_asm_source_files(intr_asm_src ${arch_SOURCE_DIR}/x86_64/intr) aux_source_directory(${arch_SOURCE_DIR}/x86_64/intr intr_cpp_src) - set(intr_src ${intr_asm_src} ${intr_cpp_src}) + set(intr_src ${intr_asm_src} ${intr_cpp_src}) endif () # 寻找 CXX 文件 @@ -52,11 +51,12 @@ set(apic_src ${apic_cpp_src}) # 设置子模块所有的源码 set(arch_src ${boot_src} ${port_src} ${gdt_src} ${intr_src} ${apic_src}) -# 添加子模块 +# 添加子模块 add_library(${PROJECT_NAME} OBJECT ${arch_src}) # 添加头文件搜索路径 target_include_arch_header_files(${PROJECT_NAME}) target_include_libc_header_files(${PROJECT_NAME}) +target_include_libcxx_header_files(${PROJECT_NAME}) target_include_common_header_files(${PROJECT_NAME}) target_include_drv_header_files(${PROJECT_NAME}) diff --git a/src/arch/ia32/apic/apic.cpp b/src/arch/ia32/apic/apic.cpp index f7eb2a840..41fbf84f9 100644 --- a/src/arch/ia32/apic/apic.cpp +++ b/src/arch/ia32/apic/apic.cpp @@ -14,11 +14,9 @@ * */ -#include "stdio.h" -#include "assert.h" -#include "intr.h" -#include "cpu.hpp" #include "apic.h" +#include "cstdio" +#include "intr.h" // 64-ia-32-architectures-software-developer-vol-3a-manual#10 diff --git a/src/arch/ia32/apic/include/apic.h b/src/arch/ia32/apic/include/apic.h index c4ba05d24..e5dc5e87c 100644 --- a/src/arch/ia32/apic/include/apic.h +++ b/src/arch/ia32/apic/include/apic.h @@ -17,14 +17,16 @@ #ifndef _APIC_H_ #define _APIC_H_ -#include "stdint.h" +#include "cstdint" /** * @brief APIC 抽象 */ class APIC { private: + protected: + public: APIC(void); ~APIC(void); @@ -36,7 +38,9 @@ class APIC { */ class LOCAL_APIC { private: + protected: + public: LOCAL_APIC(void); ~LOCAL_APIC(void); @@ -48,7 +52,9 @@ class LOCAL_APIC { */ class IO_APIC { private: + protected: + public: IO_APIC(void); ~IO_APIC(void); diff --git a/src/arch/ia32/apic/io_apic.cpp b/src/arch/ia32/apic/io_apic.cpp index 3259415e3..a96e5df37 100644 --- a/src/arch/ia32/apic/io_apic.cpp +++ b/src/arch/ia32/apic/io_apic.cpp @@ -14,10 +14,9 @@ * */ -#include "intr.h" -#include "cpu.hpp" -#include "io.h" #include "apic.h" +#include "cpu.hpp" +#include "intr.h" /// @todo diff --git a/src/arch/ia32/apic/local_apic.cpp b/src/arch/ia32/apic/local_apic.cpp index 12a60268f..5c8923409 100644 --- a/src/arch/ia32/apic/local_apic.cpp +++ b/src/arch/ia32/apic/local_apic.cpp @@ -14,11 +14,10 @@ * */ -#include "stdio.h" -#include "assert.h" -#include "intr.h" -#include "cpu.hpp" #include "apic.h" +#include "cpu.hpp" +#include "cstdio" +#include "intr.h" /// @see 64-ia-32-architectures-software-developer-vol-3a-manual#10 @@ -42,10 +41,10 @@ int32_t LOCAL_APIC::init(void) { if (cpuid.x2apic() == false) { warn("Not support x2APIC.\n"); } - uint64_t msr = CPU::READ_MSR(CPU::IA32_APIC_BASE); + uint64_t msr = CPU::READ_MSR(CPU::IA32_APIC_BASE); // 开启 xAPIC 与 x2APIC - msr |= (CPU::IA32_APIC_BASE_GLOBAL_ENABLE_BIT | - CPU::IA32_APIC_BASE_X2APIC_ENABLE_BIT); + msr |= (CPU::IA32_APIC_BASE_GLOBAL_ENABLE_BIT + | CPU::IA32_APIC_BASE_X2APIC_ENABLE_BIT); CPU::WRITE_MSR(CPU::IA32_APIC_BASE, msr); // 设置 SIVR msr = CPU::READ_MSR(CPU::IA32_X2APIC_SIVR); @@ -56,9 +55,9 @@ int32_t LOCAL_APIC::init(void) { CPU::WRITE_MSR(CPU::IA32_X2APIC_SIVR, msr); // 屏蔽所有 LVT - msr = 0; + msr = 0; msr |= CPU::IA32_X2APIC_LVT_MASK_BIT; - msr = 0x10000; + msr = 0x10000; CPU::WRITE_MSR(CPU::IA32_X2APIC_CMCI, msr); CPU::WRITE_MSR(CPU::IA32_X2APIC_LVT_TIMER, msr); CPU::WRITE_MSR(CPU::IA32_X2APIC_LVT_THERMAL, msr); diff --git a/src/arch/ia32/cpu.hpp b/src/arch/ia32/cpu.hpp index c366a8334..35efc55ae 100644 --- a/src/arch/ia32/cpu.hpp +++ b/src/arch/ia32/cpu.hpp @@ -14,535 +14,540 @@ * */ -#ifndef _CPU_HPP_ -#define _CPU_HPP_ +#ifndef SIMPLEKERNEL_CPU_HPP +#define SIMPLEKERNEL_CPU_HPP -#include "stdint.h" -#include "stdbool.h" -#include "assert.h" -#include "string.h" +#include "cstdbool" +#include "cstdint" +#include "cstdio" +#include "cstring" /** * @brief cpu 相关 * @todo CPUID 相关操作,补全寄存器操作,数据地址等 */ namespace CPU { - // CR0:包含当前处理器运行的控制标志。 - // CR1:保留。 - // CR2:包含发生页面错误时的线性地址。 - // CR3:页面目录表(Page Directory Table)的物理地址。 - // 虚拟地址启用且CR0中PG位设置为1的情况下,CR3可以协助处理器将线性地址转换为物理地址。一般情况下为MMU提供页表的入口实现。 - // CR4:包含处理器扩展功能的标志位。 - // CR8:提供对任务优先级寄存器(Task Priority - // Register)的读写(仅在64位模式下存在)。 对控制寄存器的读写是通过MOV - // CRn指令来实现 - - /// PE:CR0的位0是启用保护(Protection - // Enable)标志。当设置该位时即开启了保护模式; - // 当复位时即进入实地址模式。这个标志仅开启段级保护,而并没有启用分页机制。若要启用分页机制,那么PE和PG标志都要置位。 - static constexpr const uint32_t CR0_PE = 0x00000001; - static constexpr const uint32_t CR0_MP = 0x00000002; - static constexpr const uint32_t CR0_EM = 0x00000004; - static constexpr const uint32_t CR0_TS = 0x00000008; - static constexpr const uint32_t CR0_ET = 0x00000010; - - /// NE:对于 Intel 80486或以上的CPU,CR0 的位5是协处理器错误(Numeric - // Error)标志。 当设置该标志时,就启用了 x87 - // 协处理器错误的内部报告机制;若复位该标志,那么就使用 PC 形式的 x87 - // 协处理器错误报告机制。 当NE为复位状态并且 CPU 的 IGNNE - // 输入引脚有信号时,那么数学协处理器 x87 错误将被忽略。 当NE为复位状态并且 - // CPU 的 IGNNE 输入引脚无信号时,那么非屏蔽的数学协处理器 x87 - // 错误将导致处理器通过 FERR 引脚在外部产生一个中断, - // 并且在执行下一个等待形式浮点指令或 WAIT/FWAIT 指令之前立刻停止指令执行。 - // CPU 的 FERR 引脚用于仿真外部协处理器 80387 的 ERROR 引脚, - // 因此通常连接到中断控制器输入请求引脚上。NE 标志、IGNNE 引脚和 FERR - // 引脚用于利用外部逻辑来实现 PC 形式的外部错误报告机制。 - static constexpr const uint32_t CR0_NE = 0x00000020; - - /// WP:对于Intel 80486或以上的CPU,CR0的位16是写保护(Write - /// Proctect)标志。 - // 当设置该标志时,处理器会禁止超级用户程序(例如特权级0的程序)向用户级只读页面执行写操作;当该位复位时则反之。该标志有利于UNIX类操作系统在创建进程时实现写时复制(Copy - // on Write)技术。 - static constexpr const uint32_t CR0_WP = 0x00010020; - static constexpr const uint32_t CR0_AM = 0x00040020; - static constexpr const uint32_t CR0_NW = 0x20000000; - static constexpr const uint32_t CR0_CD = 0x40000000; - - /// PG:CR0的位31是分页(Paging)标志。当设置该位时即开启了分页机制; - // 当复位时则禁止分页机制,此时所有线性地址等同于物理地址。在开启这个标志之前必须已经或者同时开启PE标志。即若要启用分页机制,那么PE和PG标志都要置位。 - static constexpr const uint32_t CR0_PG = 0x80000000; - - /// 启用保护模式PE(Protected - // Enable)位(位0)和开启分页PG(Paging)位(位31)分别用于控制分段和分页机制。 - // PE用于控制分段机制。如果PE=1,处理器就工作在开启分段机制环境下,即运行在保护模式下。 - // 如果PE=0,则处理器关闭了分段机制,并如同8086工作于实地址模式下。PG用于控制分页机制。如果PG=1,则开启了分页机制。 - // 如果PG=0,分页机制被禁止,此时线性地址被直接作为物理地址使用。 - // 如果PE=0、PG=0,处理器工作在实地址模式下;如果PG=0、PE=1,处理器工作在没有开启分页机制的保护模式下; - // 如果PG=1、PE=0,此时由于不在保护模式下不能启用分页机制,因此处理器会产生一个一般保护异常,即这种标志组合无效; - // 如果PG=1、PE=1,则处理器工作在开启了分页机制的保护模式下。 - - static constexpr const uint32_t CR3_PWT = 0x00000008; - static constexpr const uint32_t CR3_PCD = 0x00000010; - - static constexpr const uint32_t CR4_VME = 0x00000001; - static constexpr const uint32_t CR4_PVI = 0x00000002; - static constexpr const uint32_t CR4_TSD = 0x00000004; - static constexpr const uint32_t CR4_DE = 0x00000008; - // PSE 为 1 时,32bits 的页面大小变为 4MB - // 32bits 模式的分页模式支持物理地址宽度超过 - // 32bit,这种情况下的页面大小必须是 4MB,并且处理器必须支持 PSE-3 - static constexpr const uint32_t CR4_PSE = 0x00000010; - // 物理地址拓展 - // 32bits 下寻址变为三级 - static constexpr const uint32_t CR4_PAE = 0x00000020; - static constexpr const uint32_t CR4_MCE = 0x00000040; - static constexpr const uint32_t CR4_PGE = 0x00000080; - static constexpr const uint32_t CR4_PCE = 0x00000100; - static constexpr const uint32_t CR4_OSFXSR = 0x00000200; - static constexpr const uint32_t CR4_OSXMMEXCPT = 0x00000400; - static constexpr const uint32_t CR4_VMXE = 0x00002000; - static constexpr const uint32_t CR4_SMXE = 0x00004000; - static constexpr const uint32_t CR4_PCIDE = 0x00020000; - static constexpr const uint32_t CR4_OSXSAVE = 0x00040000; - static constexpr const uint32_t CR4_SMEP = 0x00100000; - - static constexpr const uint32_t IA32_APIC_BASE = 0x1B; - static constexpr const uint32_t IA32_APIC_BASE_BSP_BIT = 1 << 8; - static constexpr const uint32_t IA32_APIC_BASE_X2APIC_ENABLE_BIT = 1 << 10; - static constexpr const uint32_t IA32_APIC_BASE_GLOBAL_ENABLE_BIT = 1 << 11; - - // x2APIC ID Register (R/O) - static constexpr const uint32_t IA32_X2APIC_APICID = 0x802; - // x2APIC Version Register (R/O) - static constexpr const uint32_t IA32_X2APIC_VERSION = 0x803; - // Support for EOI-broadcast suppression - static constexpr const uint32_t IA32_X2APIC_VERSION_EOI_SUPPORT_BIT = 1 - << 24; - // x2APIC Task Priority Register (R/W) - static constexpr const uint32_t IA32_X2APIC_TPR = 0x808; - // x2APIC Processor Priority Register (R/O) - static constexpr const uint32_t IA32_X2APIC_PPR = 0x80A; - // x2APIC EOI Register (W/O) - static constexpr const uint32_t IA32_X2APIC_EOI = 0x80B; - // x2APIC Logical Destination Register (R/O) - static constexpr const uint32_t IA32_X2APIC_LDR = 0x80D; - // x2APIC Spurious Interrupt Vector Register (R/W) - static constexpr const uint32_t IA32_X2APIC_SIVR = 0x80F; - // 伪中断向量号 - static constexpr const uint32_t IA32_X2APIC_SIVR_NO_BIT = 0x0; - // APIC 软件使能 1:enable - static constexpr const uint32_t IA32_X2APIC_SIVR_APIC_ENABLE_BIT = 1 << 8; - // 焦点处理器 0:disable - static constexpr const uint32_t IA32_X2APIC_SIVR_FOCUS_ENABLE_BIT = 1 << 9; - // 禁止广播 EOI 消息使能 1:enable - static constexpr const uint32_t IA32_X2APIC_SIVR_EOI_ENABLE_BIT = 1 << 12; - // x2APIC In-Service Register Bits 31:0 (R/O) - static constexpr const uint32_t IA32_X2APIC_ISR0 = 0x810; - static constexpr const uint32_t IA32_X2APIC_ISR1 = 0x811; - static constexpr const uint32_t IA32_X2APIC_ISR2 = 0x812; - static constexpr const uint32_t IA32_X2APIC_ISR3 = 0x813; - static constexpr const uint32_t IA32_X2APIC_ISR4 = 0x814; - static constexpr const uint32_t IA32_X2APIC_ISR5 = 0x815; - static constexpr const uint32_t IA32_X2APIC_ISR6 = 0x816; - // x2APIC In-Service Register Bits 255:224 (R/O) - static constexpr const uint32_t IA32_X2APIC_ISR7 = 0x817; - // x2APIC Trigger Mode Register Bits 31:0 (R/O) - static constexpr const uint32_t IA32_X2APIC_TMR0 = 0x818; - static constexpr const uint32_t IA32_X2APIC_TMR1 = 0x819; - static constexpr const uint32_t IA32_X2APIC_TMR2 = 0x81A; - static constexpr const uint32_t IA32_X2APIC_TMR3 = 0x81B; - static constexpr const uint32_t IA32_X2APIC_TMR4 = 0x81C; - static constexpr const uint32_t IA32_X2APIC_TMR5 = 0x81D; - static constexpr const uint32_t IA32_X2APIC_TMR6 = 0x81E; - // x2APIC Trigger Mode Register Bits 255:224 (R/O) - static constexpr const uint32_t IA32_X2APIC_TMR7 = 0x81F; - // x2APIC Interrupt Request Register Bits 31:0 (R/O) - static constexpr const uint32_t IA32_X2APIC_IRR0 = 0x820; - static constexpr const uint32_t IA32_X2APIC_IRR1 = 0x821; - static constexpr const uint32_t IA32_X2APIC_IRR2 = 0x822; - static constexpr const uint32_t IA32_X2APIC_IRR3 = 0x823; - static constexpr const uint32_t IA32_X2APIC_IRR4 = 0x824; - static constexpr const uint32_t IA32_X2APIC_IRR5 = 0x825; - static constexpr const uint32_t IA32_X2APIC_IRR6 = 0x826; - // x2APIC Interrupt Request Register Bits 255:224 (R/O) - static constexpr const uint32_t IA32_X2APIC_IRR7 = 0x827; - // x2APIC Error Status Register (R/W) - static constexpr const uint32_t IA32_X2APIC_ESR = 0x828; - // x2APIC LVT Corrected Machine Check Interrupt Register (R/W) - static constexpr const uint32_t IA32_X2APIC_CMCI = 0x82F; - // x2APIC Interrupt Command Register (R/W) - static constexpr const uint32_t IA32_X2APIC_ICR = 0x830; - // x2APIC LVT Timer Interrupt Register (R/W) - static constexpr const uint32_t IA32_X2APIC_LVT_TIMER = 0x832; - // x2APIC LVT Thermal Sensor Interrupt Register (R/W) - static constexpr const uint32_t IA32_X2APIC_LVT_THERMAL = 0x833; - // x2APIC LVT Performance Monitor Interrupt Register (R/W) - static constexpr const uint32_t IA32_X2APIC_LVT_PMI = 0x834; - // x2APIC LVT LINT0 Register (R/W) - static constexpr const uint32_t IA32_X2APIC_LVT_LINT0 = 0x835; - // x2APIC LVT LINT1 Register (R/W) - static constexpr const uint32_t IA32_X2APIC_LVT_LINT1 = 0x836; - // x2APIC LVT Error Register (R/W) - static constexpr const uint32_t IA32_X2APIC_LVT_ERROR = 0x837; - // Bits 0-7 The vector number - static constexpr const uint32_t IA32_X2APIC_LVT_NO_BIT = 0x0; - // Bits 8-11 (reserved for timer) 100b if NMI - static constexpr const uint32_t IA32_X2APIC_LVT_NMI_BIT = 1 << 8; - // Bit 12 Set if interrupt pending. - static constexpr const uint32_t IA32_X2APIC_LVT_PENDING_BIT = 1 << 12; - // Bit 13 (reserved for timer) Polarity, set is low triggered - static constexpr const uint32_t IA32_X2APIC_LVT_POLAR_BIT = 1 << 13; - // Bit 14 (reserved for timer) Remote IRR - static constexpr const uint32_t IA32_X2APIC_LVT_REMOTE_IRR_BIT = 1 << 14; - // Bit 15 (reserved for timer) trigger mode, set is level triggered - static constexpr const uint32_t IA32_X2APIC_LVT_TRIGGER_BIT = 1 << 15; - // Bit 16 Set to mask - static constexpr const uint32_t IA32_X2APIC_LVT_MASK_BIT = 1 << 16; - // Bits 17-31 Reserved - - // x2APIC Initial Count Register(R/W) - static constexpr const uint32_t IA32_X2APIC_TIMER_INIT_COUNT = 0x838; - // x2APIC Current Count Register (R/O) - static constexpr const uint32_t IA32_X2APIC_TIMER_CUR_COUNT = 0x839; - // x2APIC Divide Configuration Register (R/W) - static constexpr const uint32_t IA32_X2APIC_DIV_CONF = 0x83E; - // x2APIC Self IPI Register (W/O) - static constexpr const uint32_t IA32_X2APIC_SELF_IPI = 0x83F; - - // 段描述符 DPL - /// 内核级 - static constexpr const uint32_t DPL0 = 0x00; - static constexpr const uint32_t DPL1 = 0x01; - static constexpr const uint32_t DPL2 = 0x02; - /// 用户级 - static constexpr const uint32_t DPL3 = 0x03; - - /** - * @brief 执行CPU空操作 - */ - static inline void hlt(void) { - __asm__ volatile("hlt"); - return; - } +// CR0:包含当前处理器运行的控制标志。 +// CR1:保留。 +// CR2:包含发生页面错误时的线性地址。 +// CR3:页面目录表(Page Directory Table)的物理地址。 +// 虚拟地址启用且CR0中PG位设置为1的情况下,CR3可以协助处理器将线性地址转换为物理地址。一般情况下为MMU提供页表的入口实现。 +// CR4:包含处理器扩展功能的标志位。 +// CR8:提供对任务优先级寄存器(Task Priority +// Register)的读写(仅在64位模式下存在)。 对控制寄存器的读写是通过MOV +// CRn指令来实现 + +/// PE:CR0的位0是启用保护(Protection +// Enable)标志。当设置该位时即开启了保护模式; +// 当复位时即进入实地址模式。这个标志仅开启段级保护,而并没有启用分页机制。若要启用分页机制,那么PE和PG标志都要置位。 +static constexpr const uint32_t CR0_PE = 0x00000001; +static constexpr const uint32_t CR0_MP = 0x00000002; +static constexpr const uint32_t CR0_EM = 0x00000004; +static constexpr const uint32_t CR0_TS = 0x00000008; +static constexpr const uint32_t CR0_ET = 0x00000010; + +/// NE:对于 Intel 80486或以上的CPU,CR0 的位5是协处理器错误(Numeric +// Error)标志。 当设置该标志时,就启用了 x87 +// 协处理器错误的内部报告机制;若复位该标志,那么就使用 PC 形式的 x87 +// 协处理器错误报告机制。 当NE为复位状态并且 CPU 的 IGNNE +// 输入引脚有信号时,那么数学协处理器 x87 错误将被忽略。 当NE为复位状态并且 +// CPU 的 IGNNE 输入引脚无信号时,那么非屏蔽的数学协处理器 x87 +// 错误将导致处理器通过 FERR 引脚在外部产生一个中断, +// 并且在执行下一个等待形式浮点指令或 WAIT/FWAIT 指令之前立刻停止指令执行。 +// CPU 的 FERR 引脚用于仿真外部协处理器 80387 的 ERROR 引脚, +// 因此通常连接到中断控制器输入请求引脚上。NE 标志、IGNNE 引脚和 FERR +// 引脚用于利用外部逻辑来实现 PC 形式的外部错误报告机制。 +static constexpr const uint32_t CR0_NE = 0x00000020; + +/// WP:对于Intel 80486或以上的CPU,CR0的位16是写保护(Write +/// Proctect)标志。 +// 当设置该标志时,处理器会禁止超级用户程序(例如特权级0的程序)向用户级只读页面执行写操作;当该位复位时则反之。该标志有利于UNIX类操作系统在创建进程时实现写时复制(Copy +// on Write)技术。 +static constexpr const uint32_t CR0_WP = 0x00010020; +static constexpr const uint32_t CR0_AM = 0x00040020; +static constexpr const uint32_t CR0_NW = 0x20000000; +static constexpr const uint32_t CR0_CD = 0x40000000; + +/// PG:CR0的位31是分页(Paging)标志。当设置该位时即开启了分页机制; +// 当复位时则禁止分页机制,此时所有线性地址等同于物理地址。在开启这个标志之前必须已经或者同时开启PE标志。即若要启用分页机制,那么PE和PG标志都要置位。 +static constexpr const uint32_t CR0_PG = 0x80000000; + +/// 启用保护模式PE(Protected +// Enable)位(位0)和开启分页PG(Paging)位(位31)分别用于控制分段和分页机制。 +// PE用于控制分段机制。如果PE=1,处理器就工作在开启分段机制环境下,即运行在保护模式下。 +// 如果PE=0,则处理器关闭了分段机制,并如同8086工作于实地址模式下。PG用于控制分页机制。如果PG=1,则开启了分页机制。 +// 如果PG=0,分页机制被禁止,此时线性地址被直接作为物理地址使用。 +// 如果PE=0、PG=0,处理器工作在实地址模式下;如果PG=0、PE=1,处理器工作在没有开启分页机制的保护模式下; +// 如果PG=1、PE=0,此时由于不在保护模式下不能启用分页机制,因此处理器会产生一个一般保护异常,即这种标志组合无效; +// 如果PG=1、PE=1,则处理器工作在开启了分页机制的保护模式下。 + +static constexpr const uint32_t CR3_PWT = 0x00000008; +static constexpr const uint32_t CR3_PCD = 0x00000010; + +static constexpr const uint32_t CR4_VME = 0x00000001; +static constexpr const uint32_t CR4_PVI = 0x00000002; +static constexpr const uint32_t CR4_TSD = 0x00000004; +static constexpr const uint32_t CR4_DE = 0x00000008; +// PSE 为 1 时,32bits 的页面大小变为 4MB +// 32bits 模式的分页模式支持物理地址宽度超过 +// 32bit,这种情况下的页面大小必须是 4MB,并且处理器必须支持 PSE-3 +static constexpr const uint32_t CR4_PSE = 0x00000010; +// 物理地址拓展 +// 32bits 下寻址变为三级 +static constexpr const uint32_t CR4_PAE = 0x00000020; +static constexpr const uint32_t CR4_MCE = 0x00000040; +static constexpr const uint32_t CR4_PGE = 0x00000080; +static constexpr const uint32_t CR4_PCE = 0x00000100; +static constexpr const uint32_t CR4_OSFXSR = 0x00000200; +static constexpr const uint32_t CR4_OSXMMEXCPT = 0x00000400; +static constexpr const uint32_t CR4_VMXE = 0x00002000; +static constexpr const uint32_t CR4_SMXE = 0x00004000; +static constexpr const uint32_t CR4_PCIDE = 0x00020000; +static constexpr const uint32_t CR4_OSXSAVE = 0x00040000; +static constexpr const uint32_t CR4_SMEP = 0x00100000; + +static constexpr const uint32_t IA32_APIC_BASE = 0x1B; +static constexpr const uint32_t IA32_APIC_BASE_BSP_BIT = 1 << 8; +static constexpr const uint32_t IA32_APIC_BASE_X2APIC_ENABLE_BIT = 1 << 10; +static constexpr const uint32_t IA32_APIC_BASE_GLOBAL_ENABLE_BIT = 1 << 11; + +// x2APIC ID Register (R/O) +static constexpr const uint32_t IA32_X2APIC_APICID = 0x802; +// x2APIC Version Register (R/O) +static constexpr const uint32_t IA32_X2APIC_VERSION = 0x803; +// Support for EOI-broadcast suppression +static constexpr const uint32_t IA32_X2APIC_VERSION_EOI_SUPPORT_BIT = 1 << 24; +// x2APIC Task Priority Register (R/W) +static constexpr const uint32_t IA32_X2APIC_TPR = 0x808; +// x2APIC Processor Priority Register (R/O) +static constexpr const uint32_t IA32_X2APIC_PPR = 0x80A; +// x2APIC EOI Register (W/O) +static constexpr const uint32_t IA32_X2APIC_EOI = 0x80B; +// x2APIC Logical Destination Register (R/O) +static constexpr const uint32_t IA32_X2APIC_LDR = 0x80D; +// x2APIC Spurious Interrupt Vector Register (R/W) +static constexpr const uint32_t IA32_X2APIC_SIVR = 0x80F; +// 伪中断向量号 +static constexpr const uint32_t IA32_X2APIC_SIVR_NO_BIT = 0x0; +// APIC 软件使能 1:enable +static constexpr const uint32_t IA32_X2APIC_SIVR_APIC_ENABLE_BIT = 1 << 8; +// 焦点处理器 0:disable +static constexpr const uint32_t IA32_X2APIC_SIVR_FOCUS_ENABLE_BIT = 1 << 9; +// 禁止广播 EOI 消息使能 1:enable +static constexpr const uint32_t IA32_X2APIC_SIVR_EOI_ENABLE_BIT = 1 << 12; +// x2APIC In-Service Register Bits 31:0 (R/O) +static constexpr const uint32_t IA32_X2APIC_ISR0 = 0x810; +static constexpr const uint32_t IA32_X2APIC_ISR1 = 0x811; +static constexpr const uint32_t IA32_X2APIC_ISR2 = 0x812; +static constexpr const uint32_t IA32_X2APIC_ISR3 = 0x813; +static constexpr const uint32_t IA32_X2APIC_ISR4 = 0x814; +static constexpr const uint32_t IA32_X2APIC_ISR5 = 0x815; +static constexpr const uint32_t IA32_X2APIC_ISR6 = 0x816; +// x2APIC In-Service Register Bits 255:224 (R/O) +static constexpr const uint32_t IA32_X2APIC_ISR7 = 0x817; +// x2APIC Trigger Mode Register Bits 31:0 (R/O) +static constexpr const uint32_t IA32_X2APIC_TMR0 = 0x818; +static constexpr const uint32_t IA32_X2APIC_TMR1 = 0x819; +static constexpr const uint32_t IA32_X2APIC_TMR2 = 0x81A; +static constexpr const uint32_t IA32_X2APIC_TMR3 = 0x81B; +static constexpr const uint32_t IA32_X2APIC_TMR4 = 0x81C; +static constexpr const uint32_t IA32_X2APIC_TMR5 = 0x81D; +static constexpr const uint32_t IA32_X2APIC_TMR6 = 0x81E; +// x2APIC Trigger Mode Register Bits 255:224 (R/O) +static constexpr const uint32_t IA32_X2APIC_TMR7 = 0x81F; +// x2APIC Interrupt Request Register Bits 31:0 (R/O) +static constexpr const uint32_t IA32_X2APIC_IRR0 = 0x820; +static constexpr const uint32_t IA32_X2APIC_IRR1 = 0x821; +static constexpr const uint32_t IA32_X2APIC_IRR2 = 0x822; +static constexpr const uint32_t IA32_X2APIC_IRR3 = 0x823; +static constexpr const uint32_t IA32_X2APIC_IRR4 = 0x824; +static constexpr const uint32_t IA32_X2APIC_IRR5 = 0x825; +static constexpr const uint32_t IA32_X2APIC_IRR6 = 0x826; +// x2APIC Interrupt Request Register Bits 255:224 (R/O) +static constexpr const uint32_t IA32_X2APIC_IRR7 = 0x827; +// x2APIC Error Status Register (R/W) +static constexpr const uint32_t IA32_X2APIC_ESR = 0x828; +// x2APIC LVT Corrected Machine Check Interrupt Register (R/W) +static constexpr const uint32_t IA32_X2APIC_CMCI = 0x82F; +// x2APIC Interrupt Command Register (R/W) +static constexpr const uint32_t IA32_X2APIC_ICR = 0x830; +// x2APIC LVT Timer Interrupt Register (R/W) +static constexpr const uint32_t IA32_X2APIC_LVT_TIMER = 0x832; +// x2APIC LVT Thermal Sensor Interrupt Register (R/W) +static constexpr const uint32_t IA32_X2APIC_LVT_THERMAL = 0x833; +// x2APIC LVT Performance Monitor Interrupt Register (R/W) +static constexpr const uint32_t IA32_X2APIC_LVT_PMI = 0x834; +// x2APIC LVT LINT0 Register (R/W) +static constexpr const uint32_t IA32_X2APIC_LVT_LINT0 = 0x835; +// x2APIC LVT LINT1 Register (R/W) +static constexpr const uint32_t IA32_X2APIC_LVT_LINT1 = 0x836; +// x2APIC LVT Error Register (R/W) +static constexpr const uint32_t IA32_X2APIC_LVT_ERROR = 0x837; +// Bits 0-7 The vector number +static constexpr const uint32_t IA32_X2APIC_LVT_NO_BIT = 0x0; +// Bits 8-11 (reserved for timer) 100b if NMI +static constexpr const uint32_t IA32_X2APIC_LVT_NMI_BIT = 1 << 8; +// Bit 12 Set if interrupt pending. +static constexpr const uint32_t IA32_X2APIC_LVT_PENDING_BIT = 1 << 12; +// Bit 13 (reserved for timer) Polarity, set is low triggered +static constexpr const uint32_t IA32_X2APIC_LVT_POLAR_BIT = 1 << 13; +// Bit 14 (reserved for timer) Remote IRR +static constexpr const uint32_t IA32_X2APIC_LVT_REMOTE_IRR_BIT = 1 << 14; +// Bit 15 (reserved for timer) trigger mode, set is level triggered +static constexpr const uint32_t IA32_X2APIC_LVT_TRIGGER_BIT = 1 << 15; +// Bit 16 Set to mask +static constexpr const uint32_t IA32_X2APIC_LVT_MASK_BIT = 1 << 16; +// Bits 17-31 Reserved + +// x2APIC Initial Count Register(R/W) +static constexpr const uint32_t IA32_X2APIC_TIMER_INIT_COUNT = 0x838; +// x2APIC Current Count Register (R/O) +static constexpr const uint32_t IA32_X2APIC_TIMER_CUR_COUNT = 0x839; +// x2APIC Divide Configuration Register (R/W) +static constexpr const uint32_t IA32_X2APIC_DIV_CONF = 0x83E; +// x2APIC Self IPI Register (W/O) +static constexpr const uint32_t IA32_X2APIC_SELF_IPI = 0x83F; + +// 段描述符 DPL +/// 内核级 +static constexpr const uint32_t DPL0 = 0x00; +static constexpr const uint32_t DPL1 = 0x01; +static constexpr const uint32_t DPL2 = 0x02; +/// 用户级 +static constexpr const uint32_t DPL3 = 0x03; - /** - * @brief 开启中断 - */ - static inline void ENABLE_INTR(void) { - __asm__ volatile("sti" ::: "memory"); - return; - } +/** + * @brief 执行CPU空操作 + */ +inline static void hlt(void) { + __asm__ volatile("hlt"); + return; +} - /** - * @brief 关闭中断 - */ - static inline void DISABLE_INTR(void) { - __asm__ volatile("cli" ::: "memory"); - return; - } +/** + * @brief 开启中断 + */ +inline static void ENABLE_INTR(void) { + __asm__ volatile("sti" ::: "memory"); + return; +} - /** - * @brief 触发 debug 中断 - */ - static inline void debug_intr(void) { - __asm__ volatile("int $0x01"); - return; - } +/** + * @brief 关闭中断 + */ +inline static void DISABLE_INTR(void) { + __asm__ volatile("cli" ::: "memory"); + return; +} - /** - * @brief 读取 EFLAGS - * @return uint32_t eflags 值 - */ - static inline uint64_t READ_EFLAGS(void) { - uint64_t eflags; - __asm__ volatile("pushf\n\t" - "pop %0\n\t" - : "=r"(eflags)); - return eflags; - } +/** + * @brief 触发 debug 中断 + */ +inline static void debug_intr(void) { + __asm__ volatile("int $0x01"); + return; +} - /** - * @brief 读取 CR0 - * @return uint32_t CR0 值 - */ - static inline uint32_t READ_CR0(void) { - uint32_t cr0; - __asm__ volatile("mov %%cr0, %0" : "=b"(cr0)); - return cr0; - } +/** + * @brief 读取 EFLAGS + * @return uint32_t eflags 值 + */ +inline static uint32_t READ_EFLAGS(void) { + uint32_t eflags; + __asm__ volatile("pushf\n\t" + "pop %0\n\t" + : "=r"(eflags)); + return eflags; +} - /** - * @brief 读取 CR2 - * @return uint32_t CR2 值 - */ - static inline uint32_t READ_CR2(void) { - uint32_t cr2; - __asm__ volatile("mov %%cr2, %0" : "=b"(cr2)); - return cr2; - } +/** + * @brief 读取 CR0 + * @return uint32_t CR0 值 + */ +inline static uint32_t READ_CR0(void) { + uint32_t cr0; + __asm__ volatile("mov %%cr0, %0" : "=b"(cr0)); + return cr0; +} - /** - * @brief 获取页目录 CR3 - * @return uintptr_t CR3 值 - */ - static inline uintptr_t GET_PGD(void) { - uintptr_t cr3; - __asm__ volatile("mov %%cr3, %0" : "=b"(cr3)); - return cr3; - } +/** + * @brief 读取 CR2 + * @return uint32_t CR2 值 + */ +inline static uint32_t READ_CR2(void) { + uint32_t cr2; + __asm__ volatile("mov %%cr2, %0" : "=b"(cr2)); + return cr2; +} - /** - * @brief 切换内核栈 - * @param _stack_top 要切换的栈顶地址 - */ - static inline void switch_stack(void *_stack_top) { - asm("mov %0, %%esp" : : "r"(_stack_top)); - asm("xor %%ebp, %%ebp" : :); - return; - } +/** + * @brief 设置 页目录 + * @param _pgd 要设置的页表 + * @return true 成功 + * @return false 失败 + */ +inline static bool SET_PGD(uintptr_t _pgd) { + __asm__ volatile("mov %0, %%cr3" : : "r"(_pgd)); + return true; +} - /** - * @brief 读取 CR4 - * @return uint32_t CR4 值 - */ - static inline uint32_t READ_CR4(void) { - uint32_t cr4; - __asm__ volatile("mov %%cr4, %0" : "=b"(cr4)); - return cr4; - } +/** + * @brief 获取页目录 CR3 + * @return uintptr_t CR3 值 + */ +inline static uintptr_t GET_PGD(void) { + uintptr_t cr3; + __asm__ volatile("mov %%cr3, %0" : "=b"(cr3)); + return cr3; +} - /** - * @brief 刷新页表缓存 - * @param _addr 要刷新的地址 - */ - static inline void VMM_FLUSH(uintptr_t _addr) { - __asm__ volatile("invlpg (%0)" : : "r"(_addr) : "memory"); - return; - } +/** + * @brief 切换内核栈 + * @param _stack_top 要切换的栈顶地址 + */ +inline static void switch_stack(void* _stack_top) { + asm("mov %0, %%esp" : : "r"(_stack_top)); + asm("xor %%ebp, %%ebp" : :); + return; +} - // 开启 PG - static inline bool ENABLE_PG(void) { - uintptr_t cr0 = 0; - __asm__ volatile("mov %%cr0, %0" : "=r"(cr0)); - // 最高位 PG 位置 1,分页开启 - cr0 |= (1u << 31); - __asm__ volatile("mov %0, %%cr0" : : "r"(cr0)); - info("paging enabled.\n"); - return true; - } +/** + * @brief 读取 CR4 + * @return uint32_t CR4 值 + */ +inline static uint32_t READ_CR4(void) { + uint32_t cr4; + __asm__ volatile("mov %%cr4, %0" : "=b"(cr4)); + return cr4; +} + +/** + * @brief 刷新页表缓存 + * @param _addr 要刷新的地址 + */ +inline static void VMM_FLUSH(uintptr_t _addr) { + __asm__ volatile("invlpg (%0)" : : "r"(_addr) : "memory"); + return; +} + +// 开启 PG +inline static bool ENABLE_PG(void) { + uintptr_t cr0 = 0; + __asm__ volatile("mov %%cr0, %0" : "=r"(cr0)); + // 最高位 PG 位置 1,分页开启 + cr0 |= (1u << 31); + __asm__ volatile("mov %0, %%cr0" : : "r"(cr0)); + info("paging enabled.\n"); + return true; +} + +/** + * @brief 页表结构 32 位分页 + * @note Use of CR3 with 32-Bit Paging + */ +class cr3_t { +public: + // Ignored + uint32_t ignore1 : 3; + // Page-level write-through; indirectly determines the memory type used + // to access the page directory during linear-address translation + uint32_t pwt : 1; + // Page-level cache disable; indirectly determines the memory type used + // to access the page directory during linear-address translation + uint32_t pcd : 1; + // Ignored + uint32_t ignore2 : 7; + // Physical address of the 4-KByte aligned page directory used for + // linear-address translation + uint32_t addr : 20; +}; + +/** + * @brief 读 MSR + * @param _idx 要读的索引 + * @return uint64_t 读取的值 + */ +inline static uint64_t READ_MSR(uint32_t _idx) { + uint32_t low; + uint32_t high; + __asm__ volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(_idx)); + return ((uint64_t)high << 32) | low; +} - /** - * @brief 页表结构 32 位分页 - * @note Use of CR3 with 32-Bit Paging - */ - class cr3_t { - public: - // Ignored - uint32_t ignore1 : 3; - // Page-level write-through; indirectly determines the memory type - // used to access the page directory during linear-address - // translation - uint32_t pwt : 1; - // Page-level cache disable; indirectly determines the memory type - // used to access the page directory during linear-address - // translation - uint32_t pcd : 1; - // Ignored - uint32_t ignore2 : 7; - // Physical address of the 4-KByte aligned page directory used for - // linear-address translation - uint32_t addr : 20; +/** + * @brief 写 MSR + * @param _idx 要写的索引 + * @param _msr 要写的值 + */ +inline static void WRITE_MSR(uint32_t _idx, uint64_t _msr) { + uint32_t low = _msr; + uint32_t high = _msr >> 32; + __asm__ volatile("wrmsr" : : "a"(low), "d"(high), "c"(_idx)); + return; +} + +/// @todo 改为 static +class CPUID { +private: + static constexpr const uint32_t VENDOR_LEN = 16; + static constexpr const uint32_t BRAND_LEN = 50; + static constexpr const uint32_t FAMILY_LEN = 50; + static constexpr const uint32_t MODEL_LEN = 50; + // Vendor-strings. + static constexpr const char* VENDOR_OLDAMD = "AMDisbetter!"; + // early engineering samples of AMD K5 processor + static constexpr const char* VENDOR_AMD = "AuthenticAMD"; + static constexpr const char* VENDOR_INTEL = "GenuineIntel"; + static constexpr const char* VENDOR_Centaur = "CentaurHauls"; + static constexpr const char* VENDOR_OLDTRANSMETA = "TransmetaCPU"; + static constexpr const char* VENDOR_TRANSMETA = "GenuineTMx86"; + static constexpr const char* VENDOR_CYRIX = "CyrixInstead"; + static constexpr const char* VENDOR_CENTAUR = "CentaurHauls"; + static constexpr const char* VENDOR_NEXGEN = "NexGenDriven"; + static constexpr const char* VENDOR_UMC = "UMC UMC UMC "; + static constexpr const char* VENDOR_SIS = "SiS SiS SiS "; + static constexpr const char* VENDOR_NSC = "Geode by NSC"; + static constexpr const char* VENDOR_RISE = "RiseRiseRise"; + static constexpr const char* VENDOR_VORTEX = "Vortex86 SoC"; + static constexpr const char* VENDOR_VIA = "VIA VIA VIA "; + // Vendor-strings from Virtual Machines. + static constexpr const char* VENDOR_VMWARE = "VMwareVMware"; + static constexpr const char* VENDOR_XENHVM = "XenVMMXenVMM"; + static constexpr const char* VENDOR_MICROSOFT_HV = "Microsoft Hv"; + static constexpr const char* VENDOR_PARALLELS = " lrpepyh vr"; + + static constexpr const uint32_t FEAT_ECX_SSE3 = 1 << 0; + static constexpr const uint32_t FEAT_ECX_PCLMUL = 1 << 1; + static constexpr const uint32_t FEAT_ECX_DTES64 = 1 << 2; + static constexpr const uint32_t FEAT_ECX_MONITOR = 1 << 3; + static constexpr const uint32_t FEAT_ECX_DS_CPL = 1 << 4; + static constexpr const uint32_t FEAT_ECX_VMX = 1 << 5; + static constexpr const uint32_t FEAT_ECX_SMX = 1 << 6; + static constexpr const uint32_t FEAT_ECX_EST = 1 << 7; + static constexpr const uint32_t FEAT_ECX_TM2 = 1 << 8; + static constexpr const uint32_t FEAT_ECX_SSSE3 = 1 << 9; + static constexpr const uint32_t FEAT_ECX_CID = 1 << 10; + static constexpr const uint32_t FEAT_ECX_FMA = 1 << 12; + static constexpr const uint32_t FEAT_ECX_CX16 = 1 << 13; + static constexpr const uint32_t FEAT_ECX_ETPRD = 1 << 14; + static constexpr const uint32_t FEAT_ECX_PDCM = 1 << 15; + static constexpr const uint32_t FEAT_ECX_PCIDE = 1 << 17; + static constexpr const uint32_t FEAT_ECX_DCA = 1 << 18; + static constexpr const uint32_t FEAT_ECX_SSE4_1 = 1 << 19; + static constexpr const uint32_t FEAT_ECX_SSE4_2 = 1 << 20; + static constexpr const uint32_t FEAT_ECX_x2APIC = 1 << 21; + static constexpr const uint32_t FEAT_ECX_MOVBE = 1 << 22; + static constexpr const uint32_t FEAT_ECX_POPCNT = 1 << 23; + static constexpr const uint32_t FEAT_ECX_AES = 1 << 25; + static constexpr const uint32_t FEAT_ECX_XSAVE = 1 << 26; + static constexpr const uint32_t FEAT_ECX_OSXSAVE = 1 << 27; + static constexpr const uint32_t FEAT_ECX_AVX = 1 << 28; + static constexpr const uint32_t FEAT_EDX_FPU = 1 << 0; + static constexpr const uint32_t FEAT_EDX_VME = 1 << 1; + static constexpr const uint32_t FEAT_EDX_DE = 1 << 2; + static constexpr const uint32_t FEAT_EDX_PSE = 1 << 3; + static constexpr const uint32_t FEAT_EDX_TSC = 1 << 4; + static constexpr const uint32_t FEAT_EDX_MSR = 1 << 5; + static constexpr const uint32_t FEAT_EDX_PAE = 1 << 6; + static constexpr const uint32_t FEAT_EDX_MCE = 1 << 7; + static constexpr const uint32_t FEAT_EDX_CX8 = 1 << 8; + static constexpr const uint32_t FEAT_EDX_APIC = 1 << 9; + static constexpr const uint32_t FEAT_EDX_SEP = 1 << 11; + static constexpr const uint32_t FEAT_EDX_MTRR = 1 << 12; + static constexpr const uint32_t FEAT_EDX_PGE = 1 << 13; + static constexpr const uint32_t FEAT_EDX_MCA = 1 << 14; + static constexpr const uint32_t FEAT_EDX_CMOV = 1 << 15; + static constexpr const uint32_t FEAT_EDX_PAT = 1 << 16; + static constexpr const uint32_t FEAT_EDX_PSE36 = 1 << 17; + static constexpr const uint32_t FEAT_EDX_PSN = 1 << 18; + static constexpr const uint32_t FEAT_EDX_CLF = 1 << 19; + static constexpr const uint32_t FEAT_EDX_DTES = 1 << 21; + static constexpr const uint32_t FEAT_EDX_ACPI = 1 << 22; + static constexpr const uint32_t FEAT_EDX_MMX = 1 << 23; + static constexpr const uint32_t FEAT_EDX_FXSR = 1 << 24; + static constexpr const uint32_t FEAT_EDX_SSE = 1 << 25; + static constexpr const uint32_t FEAT_EDX_SSE2 = 1 << 26; + static constexpr const uint32_t FEAT_EDX_SS = 1 << 27; + static constexpr const uint32_t FEAT_EDX_HTT = 1 << 28; + static constexpr const uint32_t FEAT_EDX_TM1 = 1 << 29; + static constexpr const uint32_t FEAT_EDX_IA64 = 1 << 30; + static constexpr const uint32_t FEAT_EDX_PBE = 1 << 31; + + enum : uint32_t { + GET_VENDOR = 0x00, + GET_FEATURES, + GET_TLB, + GET_SERIAL, + INTEL_EXTENDED = 0x80000000, + INTEL_FEATURES, + INTEL_BRANDSTRING, + INTEL_BRANDSTRINGMORE, + INTEL_BRANDSTRINGEND, }; - /** - * @brief 设置 页目录 - * @param _pgd 要设置的页表 - * @return true 成功 - * @return false 失败 - */ - static inline bool SET_PGD(uintptr_t _pgd) { - __asm__ volatile("mov %0, %%cr3" : : "r"(_pgd)); - return true; + // TODO: 获取字符串信息 + char vendor[VENDOR_LEN]; + char brand[BRAND_LEN]; + char family_name[FAMILY_LEN]; + char model_name[MODEL_LEN]; + // 系列 + uint32_t family; + // 型号 + uint32_t model; + // 类型 + uint32_t type; + // 频率 + uint32_t stepping; + // cpu 基本信息 + uint32_t max_cpuid; + // cpu 拓展信息 + uint32_t max_cpuidex; + + void cpuid(uint32_t Mop, uint32_t Sop, uint32_t* eax, uint32_t* ebx, + uint32_t* ecx, uint32_t* edx) { + __asm__ volatile("cpuid" + : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) + : "0"(Mop), "2"(Sop)); } - /** - * @brief 读 MSR - * @param _idx 要读的索引 - * @return uint64_t 读取的值 - */ - static inline uint64_t READ_MSR(uint32_t _idx) { - uint32_t low; - uint32_t high; - __asm__ volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(_idx)); - return ((uint64_t)high << 32) | low; +public: + CPUID(void) { + uint32_t eax, ebx, ecx, edx; + // 获取 vendor ID 与基本信息 + cpuid(GET_VENDOR, 0, &eax, &ebx, &ecx, &edx); + max_cpuid = eax; + memcpy(vendor, &ebx, 4); + memcpy(vendor + 4, &edx, 4); + memcpy(vendor + 8, &ecx, 4); + vendor[12] = '\0'; + // 获取拓展信息 + cpuid(INTEL_EXTENDED, 0, &eax, &ebx, &ecx, &edx); + max_cpuidex = eax; + return; } - /** - * @brief 写 MSR - * @param _idx 要写的索引 - * @param _msr 要写的值 - */ - static inline void WRITE_MSR(uint32_t _idx, uint64_t _msr) { - uint32_t low = _msr; - uint32_t high = _msr >> 32; - __asm__ volatile("wrmsr" : : "a"(low), "d"(high), "c"(_idx)); + ~CPUID(void) { return; } - /// @todo 改为 static - class CPUID { - private: - static constexpr const uint32_t VENDOR_LEN = 16; - static constexpr const uint32_t BRAND_LEN = 50; - static constexpr const uint32_t FAMILY_LEN = 50; - static constexpr const uint32_t MODEL_LEN = 50; - // Vendor-strings. - static constexpr const char *VENDOR_OLDAMD = "AMDisbetter!"; - // early engineering samples of AMD K5 processor - static constexpr const char *VENDOR_AMD = "AuthenticAMD"; - static constexpr const char *VENDOR_INTEL = "GenuineIntel"; - static constexpr const char *VENDOR_Centaur = "CentaurHauls"; - static constexpr const char *VENDOR_OLDTRANSMETA = "TransmetaCPU"; - static constexpr const char *VENDOR_TRANSMETA = "GenuineTMx86"; - static constexpr const char *VENDOR_CYRIX = "CyrixInstead"; - static constexpr const char *VENDOR_CENTAUR = "CentaurHauls"; - static constexpr const char *VENDOR_NEXGEN = "NexGenDriven"; - static constexpr const char *VENDOR_UMC = "UMC UMC UMC "; - static constexpr const char *VENDOR_SIS = "SiS SiS SiS "; - static constexpr const char *VENDOR_NSC = "Geode by NSC"; - static constexpr const char *VENDOR_RISE = "RiseRiseRise"; - static constexpr const char *VENDOR_VORTEX = "Vortex86 SoC"; - static constexpr const char *VENDOR_VIA = "VIA VIA VIA "; - // Vendor-strings from Virtual Machines. - static constexpr const char *VENDOR_VMWARE = "VMwareVMware"; - static constexpr const char *VENDOR_XENHVM = "XenVMMXenVMM"; - static constexpr const char *VENDOR_MICROSOFT_HV = "Microsoft Hv"; - static constexpr const char *VENDOR_PARALLELS = " lrpepyh vr"; - - static constexpr const uint32_t FEAT_ECX_SSE3 = 1 << 0; - static constexpr const uint32_t FEAT_ECX_PCLMUL = 1 << 1; - static constexpr const uint32_t FEAT_ECX_DTES64 = 1 << 2; - static constexpr const uint32_t FEAT_ECX_MONITOR = 1 << 3; - static constexpr const uint32_t FEAT_ECX_DS_CPL = 1 << 4; - static constexpr const uint32_t FEAT_ECX_VMX = 1 << 5; - static constexpr const uint32_t FEAT_ECX_SMX = 1 << 6; - static constexpr const uint32_t FEAT_ECX_EST = 1 << 7; - static constexpr const uint32_t FEAT_ECX_TM2 = 1 << 8; - static constexpr const uint32_t FEAT_ECX_SSSE3 = 1 << 9; - static constexpr const uint32_t FEAT_ECX_CID = 1 << 10; - static constexpr const uint32_t FEAT_ECX_FMA = 1 << 12; - static constexpr const uint32_t FEAT_ECX_CX16 = 1 << 13; - static constexpr const uint32_t FEAT_ECX_ETPRD = 1 << 14; - static constexpr const uint32_t FEAT_ECX_PDCM = 1 << 15; - static constexpr const uint32_t FEAT_ECX_PCIDE = 1 << 17; - static constexpr const uint32_t FEAT_ECX_DCA = 1 << 18; - static constexpr const uint32_t FEAT_ECX_SSE4_1 = 1 << 19; - static constexpr const uint32_t FEAT_ECX_SSE4_2 = 1 << 20; - static constexpr const uint32_t FEAT_ECX_x2APIC = 1 << 21; - static constexpr const uint32_t FEAT_ECX_MOVBE = 1 << 22; - static constexpr const uint32_t FEAT_ECX_POPCNT = 1 << 23; - static constexpr const uint32_t FEAT_ECX_AES = 1 << 25; - static constexpr const uint32_t FEAT_ECX_XSAVE = 1 << 26; - static constexpr const uint32_t FEAT_ECX_OSXSAVE = 1 << 27; - static constexpr const uint32_t FEAT_ECX_AVX = 1 << 28; - static constexpr const uint32_t FEAT_EDX_FPU = 1 << 0; - static constexpr const uint32_t FEAT_EDX_VME = 1 << 1; - static constexpr const uint32_t FEAT_EDX_DE = 1 << 2; - static constexpr const uint32_t FEAT_EDX_PSE = 1 << 3; - static constexpr const uint32_t FEAT_EDX_TSC = 1 << 4; - static constexpr const uint32_t FEAT_EDX_MSR = 1 << 5; - static constexpr const uint32_t FEAT_EDX_PAE = 1 << 6; - static constexpr const uint32_t FEAT_EDX_MCE = 1 << 7; - static constexpr const uint32_t FEAT_EDX_CX8 = 1 << 8; - static constexpr const uint32_t FEAT_EDX_APIC = 1 << 9; - static constexpr const uint32_t FEAT_EDX_SEP = 1 << 11; - static constexpr const uint32_t FEAT_EDX_MTRR = 1 << 12; - static constexpr const uint32_t FEAT_EDX_PGE = 1 << 13; - static constexpr const uint32_t FEAT_EDX_MCA = 1 << 14; - static constexpr const uint32_t FEAT_EDX_CMOV = 1 << 15; - static constexpr const uint32_t FEAT_EDX_PAT = 1 << 16; - static constexpr const uint32_t FEAT_EDX_PSE36 = 1 << 17; - static constexpr const uint32_t FEAT_EDX_PSN = 1 << 18; - static constexpr const uint32_t FEAT_EDX_CLF = 1 << 19; - static constexpr const uint32_t FEAT_EDX_DTES = 1 << 21; - static constexpr const uint32_t FEAT_EDX_ACPI = 1 << 22; - static constexpr const uint32_t FEAT_EDX_MMX = 1 << 23; - static constexpr const uint32_t FEAT_EDX_FXSR = 1 << 24; - static constexpr const uint32_t FEAT_EDX_SSE = 1 << 25; - static constexpr const uint32_t FEAT_EDX_SSE2 = 1 << 26; - static constexpr const uint32_t FEAT_EDX_SS = 1 << 27; - static constexpr const uint32_t FEAT_EDX_HTT = 1 << 28; - static constexpr const uint32_t FEAT_EDX_TM1 = 1 << 29; - static constexpr const uint32_t FEAT_EDX_IA64 = 1 << 30; - static constexpr const uint32_t FEAT_EDX_PBE = 1 << 31; - enum : uint32_t { - GET_VENDOR = 0x00, - GET_FEATURES, - GET_TLB, - GET_SERIAL, - INTEL_EXTENDED = 0x80000000, - INTEL_FEATURES, - INTEL_BRANDSTRING, - INTEL_BRANDSTRINGMORE, - INTEL_BRANDSTRINGEND, - }; - // TODO: 获取字符串信息 - char vendor[VENDOR_LEN]; - char brand[BRAND_LEN]; - char family_name[FAMILY_LEN]; - char model_name[MODEL_LEN]; - //系列 - uint32_t family; - //型号 - uint32_t model; - //类型 - uint32_t type; - //频率 - uint32_t stepping; - // cpu 基本信息 - uint32_t max_cpuid; - // cpu 拓展信息 - uint32_t max_cpuidex; - void cpuid(uint32_t Mop, uint32_t Sop, uint32_t *eax, uint32_t *ebx, - uint32_t *ecx, uint32_t *edx) { - __asm__ volatile("cpuid" - : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) - : "0"(Mop), "2"(Sop)); - } - - public: - CPUID(void) { - uint32_t eax, ebx, ecx, edx; - // 获取 vendor ID 与基本信息 - cpuid(GET_VENDOR, 0, &eax, &ebx, &ecx, &edx); - max_cpuid = eax; - memcpy(vendor, &ebx, 4); - memcpy(vendor + 4, &edx, 4); - memcpy(vendor + 8, &ecx, 4); - vendor[12] = '\0'; - // 获取拓展信息 - cpuid(INTEL_EXTENDED, 0, &eax, &ebx, &ecx, &edx); - max_cpuidex = eax; - return; - } - ~CPUID(void) { - return; - } - bool xapic(void) { - uint32_t eax, ebx, ecx, edx; - cpuid(GET_FEATURES, 0, &eax, &ebx, &ecx, &edx); - return edx & FEAT_EDX_APIC; - } - bool x2apic(void) { - uint32_t eax, ebx, ecx, edx; - cpuid(GET_FEATURES, 0, &eax, &ebx, &ecx, &edx); - return ecx & FEAT_ECX_x2APIC; - } - bool eoi(void) { - uint64_t version = READ_MSR(IA32_X2APIC_VERSION); - return version & IA32_X2APIC_SIVR_EOI_ENABLE_BIT; - } - }; + bool xapic(void) { + uint32_t eax, ebx, ecx, edx; + cpuid(GET_FEATURES, 0, &eax, &ebx, &ecx, &edx); + return edx & FEAT_EDX_APIC; + } + + bool x2apic(void) { + uint32_t eax, ebx, ecx, edx; + cpuid(GET_FEATURES, 0, &eax, &ebx, &ecx, &edx); + return ecx & FEAT_ECX_x2APIC; + } + + bool eoi(void) { + uint64_t version = READ_MSR(IA32_X2APIC_VERSION); + return version & IA32_X2APIC_SIVR_EOI_ENABLE_BIT; + } }; -#endif /* _CPU_HPP_ */ +}; // namespace CPU + +#endif /* SIMPLEKERNEL_CPU_HPP */ diff --git a/src/arch/ia32/e820.h b/src/arch/ia32/e820.h index 829935e8f..50d6dc537 100644 --- a/src/arch/ia32/e820.h +++ b/src/arch/ia32/e820.h @@ -14,22 +14,22 @@ * */ -#ifndef _E820_H_ -#define _E820_H_ +#ifndef SIMPLEKERNEL_E820_H +#define SIMPLEKERNEL_E820_H -#include "stddef.h" -#include "stdint.h" +#include "cstddef" +#include "cstdint" /// 最大数量 -static constexpr const uint32_t E820_MAX = 8; +static constexpr const uint32_t E820_MAX = 8; /// RAM 标记 -static constexpr const uint32_t E820_RAM = 1; +static constexpr const uint32_t E820_RAM = 1; /// 保留 标记 static constexpr const uint32_t E820_RESERVED = 2; /// ACPI 标记 -static constexpr const uint32_t E820_ACPI = 3; +static constexpr const uint32_t E820_ACPI = 3; /// NVS 标记 -static constexpr const uint32_t E820_NVS = 4; +static constexpr const uint32_t E820_NVS = 4; /// 不可用 标记 static constexpr const uint32_t E820_UNUSABLE = 5; @@ -51,11 +51,13 @@ struct e820map_t { nr_map = 0; return; } + ~e820map_t(void) { return; } + uint32_t nr_map; e820entry_t map[E820_MAX]; }; -#endif /* _E820_H_ */ +#endif /* SIMPLEKERNEL_E820_H */ diff --git a/src/arch/ia32/i386/boot/boot.S b/src/arch/ia32/i386/boot/boot.S index 6ab33a518..c3397e50f 100644 --- a/src/arch/ia32/i386/boot/boot.S +++ b/src/arch/ia32/i386/boot/boot.S @@ -1,79 +1,89 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// boot.S for Simple-XX/SimpleKernel. -// 启动代码,进行一些设置后跳转到 kernel_main +/** + * @file boot.S + * @brief 启动代码,进行一些设置后跳转到 kernel_main + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-01-01 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-01-02MRNIU迁移到 doxygen + *
+ */ // 以下是来自 multiboot2 规范的定义 // How many bytes from the start of the file we search for the header. -#define MULTIBOOT_SEARCH 32768 -#define MULTIBOOT_HEADER_ALIGN 8 - -// The magic field should contain this. -#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 - -// This should be in %eax. -#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 - -// Alignment of multiboot modules. -#define MULTIBOOT_MOD_ALIGN 0x00001000 - -// Alignment of the multiboot info structure. -#define MULTIBOOT_INFO_ALIGN 0x00000008 - -// Flags set in the 'flags' member of the multiboot header. - -#define MULTIBOOT_TAG_ALIGN 8 -#define MULTIBOOT_TAG_TYPE_END 0 -#define MULTIBOOT_TAG_TYPE_CMDLINE 1 -#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 -#define MULTIBOOT_TAG_TYPE_MODULE 3 -#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 -#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 -#define MULTIBOOT_TAG_TYPE_MMAP 6 -#define MULTIBOOT_TAG_TYPE_VBE 7 -#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 -#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 -#define MULTIBOOT_TAG_TYPE_APM 10 -#define MULTIBOOT_TAG_TYPE_EFI32 11 -#define MULTIBOOT_TAG_TYPE_EFI64 12 -#define MULTIBOOT_TAG_TYPE_SMBIOS 13 -#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 -#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 -#define MULTIBOOT_TAG_TYPE_NETWORK 16 -#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 -#define MULTIBOOT_TAG_TYPE_EFI_BS 18 -#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 -#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 -#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 - -#define MULTIBOOT_HEADER_TAG_END 0 -#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 -#define MULTIBOOT_HEADER_TAG_ADDRESS 2 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 -#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 -#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 -#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 -#define MULTIBOOT_HEADER_TAG_EFI_BS 7 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 -#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 - -#define MULTIBOOT_ARCHITECTURE_I386 0 -#define MULTIBOOT_ARCHITECTURE_MIPS32 4 -#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 - -#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 -#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 -#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 - -#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 + +// The magic field should contain this. +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 + +// This should be in %eax. +#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 + +// Alignment of multiboot modules. +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +// Alignment of the multiboot info structure. +#define MULTIBOOT_INFO_ALIGN 0x00000008 + +// Flags set in the 'flags' member of the multiboot header. + +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 +#define MULTIBOOT_TAG_TYPE_EFI32 11 +#define MULTIBOOT_TAG_TYPE_EFI64 12 +#define MULTIBOOT_TAG_TYPE_SMBIOS 13 +#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +#define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 +#define MULTIBOOT_TAG_TYPE_EFI_BS 18 +#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 +#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 + +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 +#define MULTIBOOT_HEADER_TAG_EFI_BS 7 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 +#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 + +#define MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_ARCHITECTURE_MIPS32 4 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 + +#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 +#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 +#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 + +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 #define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 +// clang-format off + // 声明这一段代码以 32 位模式编译 .code32 - // multiboot2 文件头 // 计算头长度 .SET HEADER_LENGTH, multiboot_header_end - multiboot_header @@ -82,7 +92,7 @@ // 8 字节对齐 .align MULTIBOOT_HEADER_ALIGN // 声明所属段 -.section .multiboot_header +.section .text.boot multiboot_header: // 魔数 .long MULTIBOOT2_HEADER_MAGIC @@ -100,7 +110,7 @@ multiboot_header: multiboot_header_end: // 声明所属段 -.section .text +.section .text.boot // 全局可见 .global _start // 声明类型 @@ -119,7 +129,7 @@ _start: // 魔数 mov %eax, multiboot2_magic // 设置栈地址 - mov $STACK_TOP, %esp + mov $stack_top, %esp // 栈地址按照 16 字节对齐 and $0xFFFFFFF0, %esp // 帧指针修改为 0 @@ -131,9 +141,11 @@ _start: ret // 声明所属段 -.section .bss +.section .bss.boot +// 16 字节对齐 +.align 16 +.global stack_top // 栈 -STACK: +stack_top: // 跳过 16KB - .skip 4096 * 4 -STACK_TOP: + .space 4096 * 4 diff --git a/src/arch/ia32/i386/gdt/gdt.cpp b/src/arch/ia32/i386/gdt/gdt.cpp index 2db797029..e1be6b36d 100644 --- a/src/arch/ia32/i386/gdt/gdt.cpp +++ b/src/arch/ia32/i386/gdt/gdt.cpp @@ -14,63 +14,64 @@ * */ -#include "stdio.h" #include "gdt.h" +#include "cstdint" +#include "cstdio" namespace GDT { - /// 加载 GDTR - extern "C" void gdt_load(uint32_t); - /// 全局 gdt 指针 - static gdt_ptr_t gdt_ptr; - /// 全局描述符表定义 - static gdt_entry_t gdt_entries[GDT_LENGTH] __attribute__((aligned(8))); +/// 加载 GDTR +extern "C" void gdt_load(uint32_t); +/// 全局 gdt 指针 +static gdt_ptr_t gdt_ptr; +/// 全局描述符表定义 +static gdt_entry_t gdt_entries[GDT_LENGTH] __attribute__((aligned(8))); - void set_gdt(const uint8_t idx, const uint32_t base, const uint32_t limit, - const uint8_t type, const uint8_t s, const uint8_t dpl, - const uint8_t p, const uint8_t avl, const uint8_t l, - const uint8_t db, const uint8_t g) { - gdt_entries[idx].limit1 = (limit & 0xFFFF); - gdt_entries[idx].base_addr1 = (base & 0xFFFF); - gdt_entries[idx].base_addr2 = (base >> 16) & 0xFF; - gdt_entries[idx].type = type; - gdt_entries[idx].s = s; - gdt_entries[idx].dpl = dpl; - gdt_entries[idx].p = p; - gdt_entries[idx].limit2 = (limit >> 16) & 0x0F; - gdt_entries[idx].avl = avl; - gdt_entries[idx].l = l; - gdt_entries[idx].db = db; - gdt_entries[idx].g = g; - gdt_entries[idx].base_addr3 = (base >> 24) & 0xFF; - return; - } +void set_gdt(const uint8_t idx, const uint32_t base, const uint32_t limit, + const uint8_t type, const uint8_t s, const uint8_t dpl, + const uint8_t p, const uint8_t avl, const uint8_t l, + const uint8_t db, const uint8_t g) { + gdt_entries[idx].limit1 = (limit & 0xFFFF); + gdt_entries[idx].base_addr1 = (base & 0xFFFF); + gdt_entries[idx].base_addr2 = (base >> 16) & 0xFF; + gdt_entries[idx].type = type; + gdt_entries[idx].s = s; + gdt_entries[idx].dpl = dpl; + gdt_entries[idx].p = p; + gdt_entries[idx].limit2 = (limit >> 16) & 0x0F; + gdt_entries[idx].avl = avl; + gdt_entries[idx].l = l; + gdt_entries[idx].db = db; + gdt_entries[idx].g = g; + gdt_entries[idx].base_addr3 = (base >> 24) & 0xFF; + return; +} - int32_t init(void) { - // 全局描述符表界限 从 0 开始,所以总长要 - 1 - gdt_ptr.limit = sizeof(gdt_entry_t) * GDT_LENGTH - 1; - gdt_ptr.base = (uint32_t)&gdt_entries; - // 采用 Intel 平坦模型 - // Intel 文档要求首个描述符全 0 - set_gdt(GDT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); - // 内核指令段 - set_gdt(GDT_KERNEL_CODE, BASE, LIMIT, TYPE_CODE_EXECUTE_READ, - S_CODE_DATA, CPU::DPL0, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, - L_32BIT, DB_EXECUTABLE_CODE_SEGMENT_32, G_4KB); - // 内核数据段 - set_gdt(GDT_KERNEL_DATA, BASE, LIMIT, TYPE_DATA_READ_WRITE, S_CODE_DATA, - CPU::DPL0, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, L_32BIT, - DB_EXPAND_DOWN_DATA_SEGMENT_4GB, G_4KB); - // 用户模式代码段 - set_gdt(GDT_USER_CODE, BASE, LIMIT, TYPE_CODE_EXECUTE_READ, S_CODE_DATA, - CPU::DPL3, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, L_32BIT, - DB_EXECUTABLE_CODE_SEGMENT_32, G_4KB); - // 用户模式数据段 - set_gdt(GDT_USER_DATA, BASE, LIMIT, TYPE_DATA_READ_WRITE, S_CODE_DATA, - CPU::DPL3, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, L_32BIT, - DB_EXPAND_DOWN_DATA_SEGMENT_4GB, G_4KB); - // 加载全局描述符表地址到 GDTR 寄存器 - gdt_load((uint32_t)&gdt_ptr); - info("gdt init.\n"); - return 0; - } -}; +int32_t init(void) { + // 全局描述符表界限 从 0 开始,所以总长要 - 1 + gdt_ptr.limit = sizeof(gdt_entry_t) * GDT_LENGTH - 1; + gdt_ptr.base = (uint32_t)&gdt_entries; + // 采用 Intel 平坦模型 + // Intel 文档要求首个描述符全 0 + set_gdt(GDT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); + // 内核指令段 + set_gdt(GDT_KERNEL_CODE, BASE, LIMIT, TYPE_CODE_EXECUTE_READ, S_CODE_DATA, + CPU::DPL0, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, L_32BIT, + DB_EXECUTABLE_CODE_SEGMENT_32, G_4KB); + // 内核数据段 + set_gdt(GDT_KERNEL_DATA, BASE, LIMIT, TYPE_DATA_READ_WRITE, S_CODE_DATA, + CPU::DPL0, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, L_32BIT, + DB_EXPAND_DOWN_DATA_SEGMENT_4GB, G_4KB); + // 用户模式代码段 + set_gdt(GDT_USER_CODE, BASE, LIMIT, TYPE_CODE_EXECUTE_READ, S_CODE_DATA, + CPU::DPL3, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, L_32BIT, + DB_EXECUTABLE_CODE_SEGMENT_32, G_4KB); + // 用户模式数据段 + set_gdt(GDT_USER_DATA, BASE, LIMIT, TYPE_DATA_READ_WRITE, S_CODE_DATA, + CPU::DPL3, SEGMENT_PRESENT, AVL_NOT_AVAILABLE, L_32BIT, + DB_EXPAND_DOWN_DATA_SEGMENT_4GB, G_4KB); + // 加载全局描述符表地址到 GDTR 寄存器 + gdt_load((uint32_t)&gdt_ptr); + info("gdt init.\n"); + return 0; +} +}; // namespace GDT diff --git a/src/arch/ia32/i386/gdt/gdt_s.S b/src/arch/ia32/i386/gdt/gdt_s.S index 9ff9c608f..94dfc85c4 100644 --- a/src/arch/ia32/i386/gdt/gdt_s.S +++ b/src/arch/ia32/i386/gdt/gdt_s.S @@ -4,6 +4,8 @@ // // gdt_s.S for Simple-XX/SimpleKernel. +// clang-format off + .code32 .section .text diff --git a/src/arch/ia32/i386/gdt/include/gdt.h b/src/arch/ia32/i386/gdt/include/gdt.h index d102c888b..e23ffe4f4 100644 --- a/src/arch/ia32/i386/gdt/include/gdt.h +++ b/src/arch/ia32/i386/gdt/include/gdt.h @@ -14,285 +14,284 @@ * */ -#ifndef _GDT_H_ -#define _GDT_H_ +#ifndef SIMPLEKERNEL_GDT_H +#define SIMPLEKERNEL_GDT_H -#include "stdint.h" #include "cpu.hpp" +#include "cstdint" /** * @brief GDT 接口 * @see 64-ia-32-architectures-software-developer-vol-3a-manual Chapter3 */ namespace GDT { - /// 全局描述符表长度 - static constexpr const uint32_t GDT_LENGTH = 5; - /// 各个内存段所在全局描述符表下标 - static constexpr const uint32_t GDT_NULL = 0; - /// 内核代码段 - static constexpr const uint32_t GDT_KERNEL_CODE = 1; - /// 内核数据段 - static constexpr const uint32_t GDT_KERNEL_DATA = 2; - /// 用户代码段 - static constexpr const uint32_t GDT_USER_CODE = 3; - /// 用户数据段 - static constexpr const uint32_t GDT_USER_DATA = 4; - /// 内核代码段选择子 0x08 - static constexpr const uint32_t SEG_KERNEL_CODE = GDT_KERNEL_CODE << 3; - /// 内核数据段选择子 - static constexpr const uint32_t SEG_KERNEL_DATA = GDT_KERNEL_DATA << 3; - /// 用户代码段选择子 - static constexpr const uint32_t SEG_USER_CODE = GDT_USER_CODE << 3; - /// 用户数据段选择子 - static constexpr const uint32_t SEG_USER_DATA = GDT_USER_DATA << 3; +/// 全局描述符表长度 +static constexpr const uint32_t GDT_LENGTH = 5; +/// 各个内存段所在全局描述符表下标 +static constexpr const uint32_t GDT_NULL = 0; +/// 内核代码段 +static constexpr const uint32_t GDT_KERNEL_CODE = 1; +/// 内核数据段 +static constexpr const uint32_t GDT_KERNEL_DATA = 2; +/// 用户代码段 +static constexpr const uint32_t GDT_USER_CODE = 3; +/// 用户数据段 +static constexpr const uint32_t GDT_USER_DATA = 4; +/// 内核代码段选择子 0x08 +static constexpr const uint32_t SEG_KERNEL_CODE = GDT_KERNEL_CODE << 3; +/// 内核数据段选择子 +static constexpr const uint32_t SEG_KERNEL_DATA = GDT_KERNEL_DATA << 3; +/// 用户代码段选择子 +static constexpr const uint32_t SEG_USER_CODE = GDT_USER_CODE << 3; +/// 用户数据段选择子 +static constexpr const uint32_t SEG_USER_DATA = GDT_USER_DATA << 3; - // type 类型 - // Code- and Data-Segment Types, S=1 - /// 数据段 只读 - static constexpr const uint32_t TYPE_DATA_READ_ONLY = 0x00; - /// 数据段 只读,可访问 - static constexpr const uint32_t TYPE_DATA_READ_ONLY_ACCESSED = 0x01; - /// 数据段 读写 - static constexpr const uint32_t TYPE_DATA_READ_WRITE = 0x02; - /// 数据段,读写,可访问 - static constexpr const uint32_t TYPE_DATA_READ_WRITE_ACCESSED = 0x03; - /// 数据段,只读,? - static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN = 0x04; - /// 数据段,只读,?,可访问 - static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED = - 0x05; - /// 数据段,读写,? - static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN = 0x06; - /// 数据段,读写,?可访问 - static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED = - 0x07; - /// 代码段,仅执行 - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY = 0x08; - /// 代码段,仅执行,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_ACCESSED = 0x09; - /// 代码段,可执行,可读 - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ = 0x0A; - /// 代码段,可执行,可读,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_ACCESSED = 0x0B; - /// 代码段,仅执行,? - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING = 0x0C; - /// 代码段,仅执行,?,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING_ACCESSED = - 0x0D; - /// 代码段,可执行,可读,? - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING = 0x0E; - /// 代码段,可执行,可读,?,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING_ACCESSED = - 0x0F; +// type 类型 +// Code- and Data-Segment Types, S=1 +/// 数据段 只读 +static constexpr const uint32_t TYPE_DATA_READ_ONLY = 0x00; +/// 数据段 只读,可访问 +static constexpr const uint32_t TYPE_DATA_READ_ONLY_ACCESSED = 0x01; +/// 数据段 读写 +static constexpr const uint32_t TYPE_DATA_READ_WRITE = 0x02; +/// 数据段,读写,可访问 +static constexpr const uint32_t TYPE_DATA_READ_WRITE_ACCESSED = 0x03; +/// 数据段,只读,? +static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN = 0x04; +/// 数据段,只读,?,可访问 +static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED = 0x05; +/// 数据段,读写,? +static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN = 0x06; +/// 数据段,读写,?可访问 +static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED + = 0x07; +/// 代码段,仅执行 +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY = 0x08; +/// 代码段,仅执行,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_ACCESSED = 0x09; +/// 代码段,可执行,可读 +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ = 0x0A; +/// 代码段,可执行,可读,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_ACCESSED = 0x0B; +/// 代码段,仅执行,? +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING = 0x0C; +/// 代码段,仅执行,?,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING_ACCESSED + = 0x0D; +/// 代码段,可执行,可读,? +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING = 0x0E; +/// 代码段,可执行,可读,?,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING_ACCESSED + = 0x0F; - // System-Segment and Gate-Descriptor Types, 32bit, when S=0 - /// 保留 - static constexpr const uint32_t TYPE_SYSTEM_16_RESERVESD1 = 0x00; - /// 16 位 TSS - static constexpr const uint32_t TYPE_SYSTEM_16_TSS_AVAILABLE = 0x01; - /// LDT - static constexpr const uint32_t TYPE_SYSTEM_LDT = 0x02; - /// 16 位 TSS,在用 - static constexpr const uint32_t TYPE_SYSTEM_16_TSS_BUSY = 0x03; - /// 16 位调用门 - static constexpr const uint32_t TYPE_SYSTEM_16_CALL_GATE = 0x04; - /// 任务门 - static constexpr const uint32_t TYPE_SYSTEM_TASK_GATE = 0x05; - /// 16 位 中断门 - static constexpr const uint32_t TYPE_SYSTEM_16_INTERRUPT_GATE = 0x06; - /// 16 位 陷阱门 - static constexpr const uint32_t TYPE_SYSTEM_16_TRAP_GATE = 0x07; - /// 保留 - static constexpr const uint32_t TYPE_SYSTEM_32_RESERVESD2 = 0x08; - /// 32 位 TSS - static constexpr const uint32_t TYPE_SYSTEM_32_TSS_AVAILABLE = 0x09; - /// 保留 - static constexpr const uint32_t TYPE_SYSTEM_32_RESERVESD3 = 0x0A; - /// 32 位,在用 - static constexpr const uint32_t TYPE_SYSTEM_32_TSS_BUSY = 0x0B; - /// 32 位 调用门 - static constexpr const uint32_t TYPE_SYSTEM_32_CALL_GATE = 0x0C; - /// 保留 - static constexpr const uint32_t TYPE_SYSTEM_RESERVESD4 = 0x0D; - /// 32 位 中断门 - static constexpr const uint32_t TYPE_SYSTEM_32_INTERRUPT_GATE = 0x0E; - /// 32 位 陷阱门 - static constexpr const uint32_t TYPE_SYSTEM_32_TRAP_GATE = 0x0F; +// System-Segment and Gate-Descriptor Types, 32bit, when S=0 +/// 保留 +static constexpr const uint32_t TYPE_SYSTEM_16_RESERVESD1 = 0x00; +/// 16 位 TSS +static constexpr const uint32_t TYPE_SYSTEM_16_TSS_AVAILABLE = 0x01; +/// LDT +static constexpr const uint32_t TYPE_SYSTEM_LDT = 0x02; +/// 16 位 TSS,在用 +static constexpr const uint32_t TYPE_SYSTEM_16_TSS_BUSY = 0x03; +/// 16 位调用门 +static constexpr const uint32_t TYPE_SYSTEM_16_CALL_GATE = 0x04; +/// 任务门 +static constexpr const uint32_t TYPE_SYSTEM_TASK_GATE = 0x05; +/// 16 位 中断门 +static constexpr const uint32_t TYPE_SYSTEM_16_INTERRUPT_GATE = 0x06; +/// 16 位 陷阱门 +static constexpr const uint32_t TYPE_SYSTEM_16_TRAP_GATE = 0x07; +/// 保留 +static constexpr const uint32_t TYPE_SYSTEM_32_RESERVESD2 = 0x08; +/// 32 位 TSS +static constexpr const uint32_t TYPE_SYSTEM_32_TSS_AVAILABLE = 0x09; +/// 保留 +static constexpr const uint32_t TYPE_SYSTEM_32_RESERVESD3 = 0x0A; +/// 32 位,在用 +static constexpr const uint32_t TYPE_SYSTEM_32_TSS_BUSY = 0x0B; +/// 32 位 调用门 +static constexpr const uint32_t TYPE_SYSTEM_32_CALL_GATE = 0x0C; +/// 保留 +static constexpr const uint32_t TYPE_SYSTEM_RESERVESD4 = 0x0D; +/// 32 位 中断门 +static constexpr const uint32_t TYPE_SYSTEM_32_INTERRUPT_GATE = 0x0E; +/// 32 位 陷阱门 +static constexpr const uint32_t TYPE_SYSTEM_32_TRAP_GATE = 0x0F; - // S 位 - /// 系统段 - static constexpr const uint32_t S_SYSTEM = 0x00; - /// 代码/数据段 - static constexpr const uint32_t S_CODE_DATA = 0x01; +// S 位 +/// 系统段 +static constexpr const uint32_t S_SYSTEM = 0x00; +/// 代码/数据段 +static constexpr const uint32_t S_CODE_DATA = 0x01; - // 各个段的全局描述符表的选择子 - /// 内核代码段 - static constexpr const uint32_t KERNEL_CS = SEG_KERNEL_CODE | CPU::DPL0; - /// 内核数据段 - static constexpr const uint32_t KERNEL_DS = SEG_KERNEL_DATA | CPU::DPL0; - /// 用户代码段 - static constexpr const uint32_t USER_CS = SEG_USER_CODE | CPU::DPL3; - /// 用户数据段 - static constexpr const uint32_t USER_DS = SEG_USER_DATA | CPU::DPL3; +// 各个段的全局描述符表的选择子 +/// 内核代码段 +static constexpr const uint32_t KERNEL_CS = SEG_KERNEL_CODE | CPU::DPL0; +/// 内核数据段 +static constexpr const uint32_t KERNEL_DS = SEG_KERNEL_DATA | CPU::DPL0; +/// 用户代码段 +static constexpr const uint32_t USER_CS = SEG_USER_CODE | CPU::DPL3; +/// 用户数据段 +static constexpr const uint32_t USER_DS = SEG_USER_DATA | CPU::DPL3; - // P 位 - /// 无效 - static constexpr const uint32_t SEGMENT_NOT_PRESENT = 0x00; - /// 有效 - static constexpr const uint32_t SEGMENT_PRESENT = 0x01; - // AVL - /// 无效 - static constexpr const uint32_t AVL_NOT_AVAILABLE = 0x00; - /// 有效 - static constexpr const uint32_t AVL_AVAILABLE = 0x01; - // L 位 - /// 32 位 - static constexpr const uint32_t L_32BIT = 0x00; - /// 64 位 - static constexpr const uint32_t L_64BIT = 0x01; - // D/B - /// @todo - static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_16 = 0x00; - /// @todo - static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_32 = 0x01; - /// @todo - static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_16 = 0x00; - /// @todo - static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_32 = 0x01; - /// @todo - static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_64KB = 0x00; - /// @todo - static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_4GB = 0x01; - // G - /// 字节粒度 - static constexpr const uint32_t G_BYTE = 0x00; - /// 4KB 粒度 - static constexpr const uint32_t G_4KB = 0x01; +// P 位 +/// 无效 +static constexpr const uint32_t SEGMENT_NOT_PRESENT = 0x00; +/// 有效 +static constexpr const uint32_t SEGMENT_PRESENT = 0x01; +// AVL +/// 无效 +static constexpr const uint32_t AVL_NOT_AVAILABLE = 0x00; +/// 有效 +static constexpr const uint32_t AVL_AVAILABLE = 0x01; +// L 位 +/// 32 位 +static constexpr const uint32_t L_32BIT = 0x00; +/// 64 位 +static constexpr const uint32_t L_64BIT = 0x01; +// D/B +/// @todo +static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_16 = 0x00; +/// @todo +static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_32 = 0x01; +/// @todo +static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_16 = 0x00; +/// @todo +static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_32 = 0x01; +/// @todo +static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_64KB = 0x00; +/// @todo +static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_4GB = 0x01; +// G +/// 字节粒度 +static constexpr const uint32_t G_BYTE = 0x00; +/// 4KB 粒度 +static constexpr const uint32_t G_4KB = 0x01; - // 访问权限 - /// 内核读,执行 - static constexpr const uint32_t KREAD_EXEC = 0x9A; - /// 内核写 - static constexpr const uint32_t KREAD_WRITE = 0x92; - /// 用户读,执行 - static constexpr const uint32_t UREAD_EXEC = 0xFA; - /// 用户写 - static constexpr const uint32_t UREAD_WRITE = 0xF2; +// 访问权限 +/// 内核读,执行 +static constexpr const uint32_t KREAD_EXEC = 0x9A; +/// 内核写 +static constexpr const uint32_t KREAD_WRITE = 0x92; +/// 用户读,执行 +static constexpr const uint32_t UREAD_EXEC = 0xFA; +/// 用户写 +static constexpr const uint32_t UREAD_WRITE = 0xF2; - /// 段基址 - static constexpr const uint32_t BASE = 0x00; - /// 段长度 - static constexpr const uint32_t LIMIT = 0xFFFFFFFF; +/// 段基址 +static constexpr const uint32_t BASE = 0x00; +/// 段长度 +static constexpr const uint32_t LIMIT = 0xFFFFFFFF; - /** - * @brief 全局描述符 - */ - struct gdt_entry_t { - /// 段界限 15:00 - uint64_t limit1 : 16; - /// 基址 15:00 - uint64_t base_addr1 : 16; - /// 基址 23:16 - uint64_t base_addr2 : 8; - /// 类型 - uint64_t type : 4; - /// Descriptor type (0 = system; 1 = code or data) - uint64_t s : 1; - /// Specifies the privilege level of the segment - uint64_t dpl : 2; - /// Indicates whether the segment is present in memory (set) or not - /// present (clear). - uint64_t p : 1; - /// 段界限 19:16 - uint64_t limit2 : 4; - /// Available for use by system software - uint64_t avl : 1; - /// 64-bit code segment (IA-32e mode only) - uint64_t l : 1; - /// Default operation size(0 = 16 - bit segment; 1 = 32 - bit segment) - uint64_t db : 1; - /// Determines the scaling of the segment limit field. When the - /// granularity flag is clear, the segment limit is interpreted in - /// byte units; when flag is set, the segment limit is interpreted in - /// 4-KByte units. - uint64_t g : 1; - /// 基址 31:24 - uint64_t base_addr3 : 8; - } __attribute__((packed)); +/** + * @brief 全局描述符 + */ +struct gdt_entry_t { + /// 段界限 15:00 + uint64_t limit1 : 16; + /// 基址 15:00 + uint64_t base_addr1 : 16; + /// 基址 23:16 + uint64_t base_addr2 : 8; + /// 类型 + uint64_t type : 4; + /// Descriptor type (0 = system; 1 = code or data) + uint64_t s : 1; + /// Specifies the privilege level of the segment + uint64_t dpl : 2; + /// Indicates whether the segment is present in memory (set) or not + /// present (clear). + uint64_t p : 1; + /// 段界限 19:16 + uint64_t limit2 : 4; + /// Available for use by system software + uint64_t avl : 1; + /// 64-bit code segment (IA-32e mode only) + uint64_t l : 1; + /// Default operation size(0 = 16 - bit segment; 1 = 32 - bit segment) + uint64_t db : 1; + /// Determines the scaling of the segment limit field. When the + /// granularity flag is clear, the segment limit is interpreted in + /// byte units; when flag is set, the segment limit is interpreted in + /// 4-KByte units. + uint64_t g : 1; + /// 基址 31:24 + uint64_t base_addr3 : 8; +} __attribute__((packed)); - /** - * @brief 全剧描述符寄存器 - */ - struct gdt_ptr_t { - /// 全局描述符表限长 - uint16_t limit; - /// 全局描述符表 32位 基地址 - uint32_t base; - } __attribute__((packed)); +/** + * @brief 全剧描述符寄存器 + */ +struct gdt_ptr_t { + /// 全局描述符表限长 + uint16_t limit; + /// 全局描述符表 32位 基地址 + uint32_t base; +} __attribute__((packed)); - /** - * @brief 32 位 tss - * @see 64-ia-32-architectures-software-developer-vol-3a-manual#7.2.1 - * @note 目前没有使用 - */ - struct tss32_t { - uint16_t prev_task_link; - uint16_t reserved0; - uint32_t esp0; - uint16_t ss0; - uint32_t reserved1; - uint32_t esp1; - uint16_t ss1; - uint32_t reserved2; - uint32_t esp2; - uint16_t ss2; - uint32_t reserved3; - uint32_t cr3; - uint32_t eip; - uint32_t eflags; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint16_t es; - uint16_t reserved4; - uint16_t cs; - uint16_t reserved5; - uint16_t ss; - uint16_t reserved6; - uint16_t ds; - uint16_t reserved7; - uint16_t fs; - uint16_t reserved8; - uint16_t gs; - uint16_t reserved9; - uint16_t ldt_segment_selector; - uint16_t reserved10; - uint32_t t : 1; - uint32_t reserved11 : 15; - uint32_t io_map_base_addr : 16; - } __attribute__((packed)); +/** + * @brief 32 位 tss + * @see 64-ia-32-architectures-software-developer-vol-3a-manual#7.2.1 + * @note 目前没有使用 + */ +struct tss32_t { + uint16_t prev_task_link; + uint16_t reserved0; + uint32_t esp0; + uint16_t ss0; + uint32_t reserved1; + uint32_t esp1; + uint16_t ss1; + uint32_t reserved2; + uint32_t esp2; + uint16_t ss2; + uint32_t reserved3; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint16_t es; + uint16_t reserved4; + uint16_t cs; + uint16_t reserved5; + uint16_t ss; + uint16_t reserved6; + uint16_t ds; + uint16_t reserved7; + uint16_t fs; + uint16_t reserved8; + uint16_t gs; + uint16_t reserved9; + uint16_t ldt_segment_selector; + uint16_t reserved10; + uint32_t t : 1; + uint32_t reserved11 : 15; + uint32_t io_map_base_addr : 16; +} __attribute__((packed)); - /** - * @brief 全局描述符表构造函数 - * @param _num 描述符索引 - * @param _base 基地 - * @param _limit 长度 - * @param _access 访问权限 - * @param _gran 粒度 - */ - void set_gdt(int32_t _num, uint32_t _base, uint32_t _limit, uint8_t _access, - uint8_t _gran); +/** + * @brief 全局描述符表构造函数 + * @param _num 描述符索引 + * @param _base 基地 + * @param _limit 长度 + * @param _access 访问权限 + * @param _gran 粒度 + */ +void set_gdt(int32_t _num, uint32_t _base, uint32_t _limit, uint8_t _access, + uint8_t _gran); - /** - * @brief 初始化 - * @return int32_t 成功返回 0 - */ - int32_t init(void); -}; +/** + * @brief 初始化 + * @return int32_t 成功返回 0 + */ +int32_t init(void); +}; // namespace GDT -#endif /* _GDT_H_ */ +#endif /* SIMPLEKERNEL_GDT_H */ diff --git a/src/arch/ia32/i386/intr/include/intr.h b/src/arch/ia32/i386/intr/include/intr.h index b0b22a6a8..b48ba4bf1 100644 --- a/src/arch/ia32/i386/intr/include/intr.h +++ b/src/arch/ia32/i386/intr/include/intr.h @@ -14,10 +14,10 @@ * */ -#ifndef _INTR_H_ -#define _INTR_H_ +#ifndef SIMPLEKERNEL_INTR_H +#define SIMPLEKERNEL_INTR_H -#include "stdint.h" +#include "cstdint" /// @todo 升级为 APIC class INTR { @@ -26,9 +26,9 @@ class INTR { * @brief 错误码结构 */ struct error_code_t { - uint32_t ext : 1; - uint32_t idt : 1; - uint32_t ti : 1; + uint32_t ext : 1; + uint32_t idt : 1; + uint32_t ti : 1; uint32_t sec_idx : 28; }; @@ -36,14 +36,14 @@ class INTR { * @brief 缺页错误码结构 */ struct page_fault_error_code_t { - uint32_t p : 1; - uint32_t wr : 1; - uint32_t us : 1; - uint32_t rsvd : 1; - uint32_t id : 1; - uint32_t pk : 1; + uint32_t p : 1; + uint32_t wr : 1; + uint32_t us : 1; + uint32_t rsvd : 1; + uint32_t id : 1; + uint32_t pk : 1; uint32_t reserved1 : 9; - uint32_t sgx : 1; + uint32_t sgx : 1; uint32_t reserved2 : 16; }; @@ -98,23 +98,23 @@ class INTR { }; // 定义中断处理函数指针 - typedef void (*interrupt_handler_t)(intr_context_t *); + typedef void (*interrupt_handler_t)(intr_context_t*); private: /// 中断表最大值 - static constexpr const uint32_t INTERRUPT_MAX = 256; + static constexpr const uint32_t INTERRUPT_MAX = 256; /// 8259A 相关定义 /// Master (IRQs 0-7) - static constexpr const uint32_t IO_PIC1 = 0x20; + static constexpr const uint32_t IO_PIC1 = 0x20; /// Slave (IRQs 8-15) - static constexpr const uint32_t IO_PIC2 = 0xA0; - static constexpr const uint32_t IO_PIC1C = IO_PIC1 + 1; - static constexpr const uint32_t IO_PIC2C = IO_PIC2 + 1; + static constexpr const uint32_t IO_PIC2 = 0xA0; + static constexpr const uint32_t IO_PIC1C = IO_PIC1 + 1; + static constexpr const uint32_t IO_PIC2C = IO_PIC2 + 1; /// End-of-interrupt command code - static constexpr const uint32_t PIC_EOI = 0x20; + static constexpr const uint32_t PIC_EOI = 0x20; /// 中断名数组 - static constexpr const char *const intrnames[] = { + static constexpr const char* const intrnames[] = { "Divide Error", "Debug Exception", "NMI Interrupt", @@ -144,21 +144,21 @@ class INTR { */ struct idt_entry32_t { // 低位地址 - uint64_t offset0 : 16; + uint64_t offset0 : 16; // 选择子 uint64_t selector : 16; // 保留 uint64_t reserved : 4; // 填充 0 - uint64_t zero : 4; + uint64_t zero : 4; // 类型 - uint64_t type : 5; + uint64_t type : 5; // 权限 - uint64_t dpl : 2; + uint64_t dpl : 2; // 存在位 - uint64_t p : 1; + uint64_t p : 1; // 中段地址 - uint64_t offset1 : 16; + uint64_t offset1 : 16; } __attribute__((packed)); /** @@ -174,10 +174,10 @@ class INTR { /// 中断处理函数指针数组 static interrupt_handler_t interrupt_handlers[INTERRUPT_MAX] - __attribute__((aligned(4))); + __attribute__((aligned(4))); /// 中断描述符表 static idt_entry32_t idt_entry32[INTERRUPT_MAX] - __attribute__((aligned(16))); + __attribute__((aligned(16))); /// IDTR static idt_ptr_t idt_ptr; @@ -190,24 +190,24 @@ class INTR { * @param _dpl ? * @param _p ? */ - void set_idt(uint8_t _num, uint32_t _base, uint16_t _selector, - uint8_t _type, uint8_t _dpl, uint8_t _p); + void set_idt(uint8_t _num, uint32_t _base, uint16_t _selector, + uint8_t _type, uint8_t _dpl, uint8_t _p); /** * @brief 8259A 芯片初始化 */ - void init_interrupt_chip(void); + void init_interrupt_chip(void); /** * @brief 重设 8259A 芯片 * @param _no 要重设的中断号 */ - void clear_interrupt_chip(uint8_t _no); + void clear_interrupt_chip(uint8_t _no); /** * @brief 关闭 8259A 芯片的所有中断,为启动 APIC 作准备 */ - void disable_interrupt_chip(void); + void disable_interrupt_chip(void); public: // External(hardware generated) interrupts. @@ -228,60 +228,60 @@ class INTR { static constexpr const uint32_t INT_GENERAL_PROTECT = 13; static constexpr const uint32_t INT_PAGE_FAULT = 14; // 15 没有使用 - static constexpr const uint32_t INT_X87_FPU = 16; - static constexpr const uint32_t INT_ALIGNMENT = 17; - static constexpr const uint32_t INT_MACHINE_CHECK = 18; - static constexpr const uint32_t INT_SIMD_FLOAT = 19; - static constexpr const uint32_t INT_VIRTUAL_EXCE = 20; + static constexpr const uint32_t INT_X87_FPU = 16; + static constexpr const uint32_t INT_ALIGNMENT = 17; + static constexpr const uint32_t INT_MACHINE_CHECK = 18; + static constexpr const uint32_t INT_SIMD_FLOAT = 19; + static constexpr const uint32_t INT_VIRTUAL_EXCE = 20; // 21~31 保留 // 定义IRQ // 电脑系统计时器 - static constexpr const uint32_t IRQ0 = 32; + static constexpr const uint32_t IRQ0 = 32; // 键盘 - static constexpr const uint32_t IRQ1 = 33; + static constexpr const uint32_t IRQ1 = 33; // 与 IRQ9 相接,MPU-401 MD 使用 - static constexpr const uint32_t IRQ2 = 34; + static constexpr const uint32_t IRQ2 = 34; // 串口设备 - static constexpr const uint32_t IRQ3 = 35; + static constexpr const uint32_t IRQ3 = 35; // 串口设备 - static constexpr const uint32_t IRQ4 = 36; + static constexpr const uint32_t IRQ4 = 36; // 建议声卡使用 - static constexpr const uint32_t IRQ5 = 37; + static constexpr const uint32_t IRQ5 = 37; // 软驱传输控制使用 - static constexpr const uint32_t IRQ6 = 38; + static constexpr const uint32_t IRQ6 = 38; // 打印机传输控制使用 - static constexpr const uint32_t IRQ7 = 39; + static constexpr const uint32_t IRQ7 = 39; // 即时时钟 - static constexpr const uint32_t IRQ8 = 40; + static constexpr const uint32_t IRQ8 = 40; // 与 IRQ2 相接,可设定给其他硬件 - static constexpr const uint32_t IRQ9 = 41; + static constexpr const uint32_t IRQ9 = 41; // 建议网卡使用 - static constexpr const uint32_t IRQ10 = 42; + static constexpr const uint32_t IRQ10 = 42; // 建议 AGP 显卡使用 - static constexpr const uint32_t IRQ11 = 43; + static constexpr const uint32_t IRQ11 = 43; // 接 PS/2 鼠标,也可设定给其他硬件 - static constexpr const uint32_t IRQ12 = 44; + static constexpr const uint32_t IRQ12 = 44; // 协处理器使用 - static constexpr const uint32_t IRQ13 = 45; + static constexpr const uint32_t IRQ13 = 45; // SATA 主硬盘 - static constexpr const uint32_t IRQ14 = 46; + static constexpr const uint32_t IRQ14 = 46; // SATA 从硬盘 - static constexpr const uint32_t IRQ15 = 47; + static constexpr const uint32_t IRQ15 = 47; // 系统调用 - static constexpr const uint32_t IRQ128 = 128; + static constexpr const uint32_t IRQ128 = 128; /** * @brief 获取单例 * @return INTR& 静态对象 */ - static INTR &get_instance(void); + static INTR& get_instance(void); /** * @brief 中断初始化 * @return int32_t desc */ - int32_t init(void); + int32_t init(void); /** * @brief 执行中断 @@ -289,9 +289,9 @@ class INTR { * @param _intr_context 上下文 * @return int32_t 保存中断处理后的返回值 */ - int32_t call_irq(uint8_t _no, intr_context_t *_intr_context); + int32_t call_irq(uint8_t _no, intr_context_t* _intr_context); - int32_t call_isr(uint8_t _no, intr_context_t *_intr_context); + int32_t call_isr(uint8_t _no, intr_context_t* _intr_context); /** * @brief 注册一个中断处理函数 @@ -316,7 +316,7 @@ class INTR { * @param _no 中断号 * @return const char* 对应的中断名 */ - const char *get_intr_name(uint8_t _no); + const char* get_intr_name(uint8_t _no); }; /** @@ -328,12 +328,12 @@ class TIMER { * @brief 获取单例 * @return TIMER& 静态对象 */ - static TIMER &get_instance(void); + static TIMER& get_instance(void); /** * @brief 初始化 */ - void init(void); + void init(void); }; -#endif /* _INTR_H_ */ +#endif /* SIMPLEKERNEL_INTR_H */ diff --git a/src/arch/ia32/i386/intr/intr.cpp b/src/arch/ia32/i386/intr/intr.cpp index 1a8238a9a..ae6c7d6bc 100644 --- a/src/arch/ia32/i386/intr/intr.cpp +++ b/src/arch/ia32/i386/intr/intr.cpp @@ -15,14 +15,13 @@ * */ -#include "io.h" -#include "cpu.hpp" -#include "stdio.h" -#include "gdt.h" #include "intr.h" #include "apic.h" +#include "cpu.hpp" +#include "cstdio" +#include "gdt.h" +#include "io.h" #include "keyboard.h" -#include "vmm.h" // 声明中断处理函数 0 ~ 19 属于 CPU 的异常中断 // ISR:中断服务程序(interrupt service routine) @@ -110,7 +109,7 @@ extern "C" void idt_load(uint32_t); /** * @brief IRQ 处理函数 */ -extern "C" void irq_handler(uint8_t _no, INTR::intr_context_t *_intr_context) { +extern "C" void irq_handler(uint8_t _no, INTR::intr_context_t* _intr_context) { INTR::get_instance().call_irq(_no, _intr_context); return; } @@ -118,15 +117,15 @@ extern "C" void irq_handler(uint8_t _no, INTR::intr_context_t *_intr_context) { /** * @brief ISR 处理函数 */ -extern "C" void isr_handler(uint8_t _no, INTR::intr_context_t *_intr_context, - INTR::error_code_t *_err_code) { +extern "C" void isr_handler(uint8_t _no, INTR::intr_context_t* _intr_context, + INTR::error_code_t* _err_code) { (void)_err_code; INTR::get_instance().call_isr(_no, _intr_context); return; } // 默认处理函数 -static void handler_default(INTR::intr_context_t *) { +static void handler_default(INTR::intr_context_t*) { while (1) { ; } @@ -136,9 +135,9 @@ static void handler_default(INTR::intr_context_t *) { // 中断处理函数指针数组 INTR::interrupt_handler_t INTR::interrupt_handlers[INTERRUPT_MAX]; // 中断描述符表 -INTR::idt_entry32_t INTR::idt_entry32[INTERRUPT_MAX]; +INTR::idt_entry32_t INTR::idt_entry32[INTERRUPT_MAX]; // IDTR -INTR::idt_ptr_t INTR::idt_ptr; +INTR::idt_ptr_t INTR::idt_ptr; // 64-ia-32-architectures-software-developer-vol-3a-manual#6.11 void INTR::set_idt(uint8_t _num, uint32_t _base, uint16_t _selector, @@ -207,7 +206,7 @@ void INTR::disable_interrupt_chip(void) { return; } -INTR &INTR::get_instance(void) { +INTR& INTR::get_instance(void) { /// 定义全局 INTR 对象 static INTR intr; return intr; @@ -356,7 +355,7 @@ int32_t INTR::init(void) { return 0; } -int32_t INTR::call_irq(uint8_t _no, intr_context_t *_intr_context) { +int32_t INTR::call_irq(uint8_t _no, intr_context_t* _intr_context) { // 重设PIC芯片 clear_interrupt_chip(_no); if (interrupt_handlers[_no] != nullptr) { @@ -365,7 +364,7 @@ int32_t INTR::call_irq(uint8_t _no, intr_context_t *_intr_context) { return 0; } -int32_t INTR::call_isr(uint8_t _no, intr_context_t *_intr_context) { +int32_t INTR::call_isr(uint8_t _no, intr_context_t* _intr_context) { if (interrupt_handlers[_no] != nullptr) { interrupt_handlers[_no](_intr_context); } @@ -410,8 +409,8 @@ void INTR::disable_irq(uint8_t _no) { return; } -const char *INTR::get_intr_name(uint8_t _no) { - if (_no < sizeof(intrnames) / sizeof(const char *const)) { +const char* INTR::get_intr_name(uint8_t _no) { + if (_no < sizeof(intrnames) / sizeof(const char* const)) { return intrnames[_no]; } return "(unknown trap)"; diff --git a/src/arch/ia32/i386/intr/intr_s.S b/src/arch/ia32/i386/intr/intr_s.S index db08dfb48..429ef3cf6 100644 --- a/src/arch/ia32/i386/intr/intr_s.S +++ b/src/arch/ia32/i386/intr/intr_s.S @@ -1,8 +1,11 @@ -// This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +// This file is a part of Simple-XX/SimpleKernel +// (https://github.com/Simple-XX/SimpleKernel). # // intr_s.s for Simple-XX/SimpleKernel. +// clang-format off + .code32 // 加载 idt diff --git a/src/arch/ia32/i386/intr/timer.cpp b/src/arch/ia32/i386/intr/timer.cpp index 1fff2cc79..e5a0b8aa1 100644 --- a/src/arch/ia32/i386/intr/timer.cpp +++ b/src/arch/ia32/i386/intr/timer.cpp @@ -14,21 +14,18 @@ * */ -#include "stdint.h" -#include "stdio.h" -#include "cpu.hpp" +#include "cstdio" #include "intr.h" -#include "io.h" /** * @brief 时钟中断 */ -void timer_intr(INTR::intr_context_t *) { +void timer_intr(INTR::intr_context_t*) { printf("timer.\n"); return; } -TIMER &TIMER::get_instance(void) { +TIMER& TIMER::get_instance(void) { /// 定义全局 TIMER 对象 static TIMER timer; return timer; diff --git a/src/arch/ia32/i386/link.ld b/src/arch/ia32/i386/link.ld index 7a2f50f47..24c1bd9ab 100644 --- a/src/arch/ia32/i386/link.ld +++ b/src/arch/ia32/i386/link.ld @@ -2,75 +2,244 @@ /* This file is a part of Simple-XX/SimpleKernel * (https://github.com/Simple-XX/SimpleKernel). * - * link.ld for Simple-XX/SimpleKernel. - * 链接脚本,指定生成的二进制文件的布局 */ + * link.ld for Simple-XX/SimpleKernel. + * 链接脚本,指定生成的二进制文件的布局 + */ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2022 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ /* 指定输出格式 */ -OUTPUT_FORMAT(elf32-i386) -/* 执行输出架构 */ +OUTPUT_FORMAT( + "elf32-i386", + "elf32-i386", + "elf32-i386" +) +/* 指定输出架构 */ OUTPUT_ARCH(i386) /* 设置入口点 */ ENTRY(_start) /* 设置各个 section */ SECTIONS { - /* VMA 为顺序排列,LMA 按照 AT(addr) 排列 */ - . = 0; - PROVIDE(kernel_start = .); - /* 指定内核从地址 1M 处开始 */ - /* 0~1M 的空间为 BIOS 保留区域 */ - /* TODO: 这里似乎可以修改为任意地址 */ - . = 1M; - - PROVIDE(kernel_text_start = .); - /* 代码段 */ - .text : ALIGN(4K) { - *(.multiboot_header) - *(.text*) + PROVIDE (__executable_start = SEGMENT_START("text-segment", 1M)); + . = SEGMENT_START("text-segment", 1M); + .boot : { *(.text.boot) *(.data.boot) *(.bss.boot) } + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - PROVIDE(kernel_text_end = .); - - PROVIDE(kernel_rodata_start = .); - /* 只读数据段 */ - .rodata : ALIGN(4K) { - /* 构造函数起点 */ - PROVIDE(ctors_start = .); - *(SORT_BY_INIT_PRIORITY (.init_array.*)) - *(SORT_BY_INIT_PRIORITY (.ctors.*)) - *(.init_array .ctors) - /* 构造函数终点 */ - PROVIDE(ctors_end = .); - /* 析构函数起点 */ - PROVIDE(dtors_start = .); - *(.dtor*) - /* 析构函数终点 */ - PROVIDE(dtors_end = .); - *(.rodata*) - *(.gcc_except_table) - } - PROVIDE(kernel_rodata_end = .); - - PROVIDE(kernel_data_start = .); - /* 数据段 */ - .data : ALIGN(4K) { - *(.data*) - *(.eh_frame) - *(.got*) - } - PROVIDE(kernel_data_end = .); - - PROVIDE(kernel_bss_start = .); - /* 未初始化数据段 */ - .bss : ALIGN(4K) { - *(.bss) + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } - PROVIDE(kernel_bss_end = .); - - PROVIDE(kernel_debug_start = .); - /* 调试信息 */ - .debug : ALIGN(4K) { - *(.debug*) + .relr.dyn : { *(.relr.dyn) } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : { + KEEP (*(SORT_NONE(.init))) } - PROVIDE(kernel_debug_end = .); - - PROVIDE(kernel_end = .); + .plt : { *(.plt) *(.iplt) } + .plt.got : { *(.plt.got) } + .plt.sec : { *(.plt.sec) } + .text : { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1. */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions. */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2. */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2. */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions. */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3. */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF 5. */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + .debug_sup 0 : { *(.debug_sup) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } diff --git a/src/arch/ia32/port/include/port.h b/src/arch/ia32/port/include/port.h index a877d60a5..24dd94fba 100644 --- a/src/arch/ia32/port/include/port.h +++ b/src/arch/ia32/port/include/port.h @@ -14,62 +14,62 @@ * */ -#ifndef _PORT_H_ -#define _PORT_H_ +#ifndef SIMPLEKERNEL_PORT_H +#define SIMPLEKERNEL_PORT_H -#include "stdint.h" +#include "cstdint" /** * @brief 端口读写封装 */ namespace PORT { - /** - * @brief 读一个字节 - * @param _port 要读的端口 - * @return uint8_t 读取到的数据 - * @warning 不处理执行失败的问题 - */ - uint8_t inb(const uint32_t _port); +/** + * @brief 读一个字节 + * @param _port 要读的端口 + * @return uint8_t 读取到的数据 + * @warning 不处理执行失败的问题 + */ +uint8_t inb(const uint32_t _port); - /** - * @brief 读一个字 - * @param _port 要读的端口 - * @return uint16_t 读取到的数据 - * @warning 不处理执行失败的问题 - */ - uint16_t inw(const uint32_t _port); +/** + * @brief 读一个字 + * @param _port 要读的端口 + * @return uint16_t 读取到的数据 + * @warning 不处理执行失败的问题 + */ +uint16_t inw(const uint32_t _port); - /** - * @brief 读一个双字 - * @param _port 要读的端口 - * @return uint32_t 读取到的数据 - * @warning 不处理执行失败的问题 - */ - uint32_t ind(const uint32_t _port); +/** + * @brief 读一个双字 + * @param _port 要读的端口 + * @return uint32_t 读取到的数据 + * @warning 不处理执行失败的问题 + */ +uint32_t ind(const uint32_t _port); - /** - * @brief 写一个字节 - * @param _port 要写的端口 - * @param _data 要写的数据 - * @warning 不处理执行失败的问题 - */ - void outb(const uint32_t _port, const uint8_t _data); +/** + * @brief 写一个字节 + * @param _port 要写的端口 + * @param _data 要写的数据 + * @warning 不处理执行失败的问题 + */ +void outb(const uint32_t _port, const uint8_t _data); - /** - * @brief 写一个字 - * @param _port 要写的端口 - * @param _data 要写的数据 - * @warning 不处理执行失败的问题 - */ - void outw(const uint32_t _port, const uint16_t _data); +/** + * @brief 写一个字 + * @param _port 要写的端口 + * @param _data 要写的数据 + * @warning 不处理执行失败的问题 + */ +void outw(const uint32_t _port, const uint16_t _data); - /** - * @brief 写一个双字 - * @param _port 要写的端口 - * @param _data 要写的数据 - * @warning 不处理执行失败的问题 - */ - void outd(const uint32_t _port, const uint32_t _data); -}; +/** + * @brief 写一个双字 + * @param _port 要写的端口 + * @param _data 要写的数据 + * @warning 不处理执行失败的问题 + */ +void outd(const uint32_t _port, const uint32_t _data); +}; // namespace PORT -#endif /* _PORT_H_ */ +#endif /* SIMPLEKERNEL_PORT_H */ diff --git a/src/arch/ia32/x86_64/boot/boot.S b/src/arch/ia32/x86_64/boot/boot.S index bae2ec0b5..6e434d7fb 100644 --- a/src/arch/ia32/x86_64/boot/boot.S +++ b/src/arch/ia32/x86_64/boot/boot.S @@ -1,89 +1,99 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// boot.S for Simple-XX/SimpleKernel. -// 启动代码,进行一些设置后跳转到 kernel_main +/** + * @file boot.S + * @brief 启动代码,进行一些设置后跳转到 kernel_main + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-01-01 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-01-02MRNIU迁移到 doxygen + *
+ */ // 以下是来自 multiboot2 规范的定义 // How many bytes from the start of the file we search for the header. -#define MULTIBOOT_SEARCH 32768 -#define MULTIBOOT_HEADER_ALIGN 8 +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 -// The magic field should contain this. -#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 +// The magic field should contain this. +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 -// This should be in %eax. -#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 +// This should be in %eax. +#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 -// Alignment of multiboot modules. -#define MULTIBOOT_MOD_ALIGN 0x00001000 +// Alignment of multiboot modules. +#define MULTIBOOT_MOD_ALIGN 0x00001000 -// Alignment of the multiboot info structure. -#define MULTIBOOT_INFO_ALIGN 0x00000008 +// Alignment of the multiboot info structure. +#define MULTIBOOT_INFO_ALIGN 0x00000008 -// Flags set in the 'flags' member of the multiboot header. +// Flags set in the 'flags' member of the multiboot header. -#define MULTIBOOT_TAG_ALIGN 8 -#define MULTIBOOT_TAG_TYPE_END 0 -#define MULTIBOOT_TAG_TYPE_CMDLINE 1 -#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 -#define MULTIBOOT_TAG_TYPE_MODULE 3 -#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 -#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 -#define MULTIBOOT_TAG_TYPE_MMAP 6 -#define MULTIBOOT_TAG_TYPE_VBE 7 -#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 -#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 -#define MULTIBOOT_TAG_TYPE_APM 10 -#define MULTIBOOT_TAG_TYPE_EFI32 11 -#define MULTIBOOT_TAG_TYPE_EFI64 12 -#define MULTIBOOT_TAG_TYPE_SMBIOS 13 -#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 -#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 -#define MULTIBOOT_TAG_TYPE_NETWORK 16 -#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 -#define MULTIBOOT_TAG_TYPE_EFI_BS 18 -#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 -#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 -#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 +#define MULTIBOOT_TAG_TYPE_EFI32 11 +#define MULTIBOOT_TAG_TYPE_EFI64 12 +#define MULTIBOOT_TAG_TYPE_SMBIOS 13 +#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +#define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 +#define MULTIBOOT_TAG_TYPE_EFI_BS 18 +#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 +#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 -#define MULTIBOOT_HEADER_TAG_END 0 -#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 -#define MULTIBOOT_HEADER_TAG_ADDRESS 2 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 -#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 -#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 -#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 -#define MULTIBOOT_HEADER_TAG_EFI_BS 7 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 -#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 +#define MULTIBOOT_HEADER_TAG_EFI_BS 7 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 +#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 -#define MULTIBOOT_ARCHITECTURE_I386 0 -#define MULTIBOOT_ARCHITECTURE_MIPS32 4 -#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 +#define MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_ARCHITECTURE_MIPS32 4 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 -#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 -#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 -#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 +#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 +#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 +#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 -#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 #define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 - // 直接用 -m64 编译出来的是 64 位代码, // 但是启动后的机器是 32 位的,相当于在 32 位机器上跑 64 位程序。 -// 得加一层跳转到 64 位的 -m32 代码,开启 long 模式后再跳转到以 -m64 编译的代码中 -// 对于 x86_64,需要在启动阶段进入长模式(IA32E),这意味着需要一个临时页表 -// See https://wiki.osdev.org/Creating_a_64-bit_kernel: -// With a 32-bit bootstrap in your kernel +// 得加一层跳转到 64 位的 -m32 代码,开启 long 模式后再跳转到以 -m64 +// 编译的代码中 对于 +// x86_64,需要在启动阶段进入长模式(IA32E),这意味着需要一个临时页表 See +// https://wiki.osdev.org/Creating_a_64-bit_kernel: With a 32-bit bootstrap in +// your kernel + +// clang-format off // 这部分是从保护模式启动 long 模式的代码 // 工作在 32bit // 声明这一段代码以 32 位模式编译 .code32 - // multiboot2 文件头 // 计算头长度 .SET HEADER_LENGTH, multiboot_header_end - multiboot_header @@ -92,7 +102,7 @@ // 8 字节对齐 .align MULTIBOOT_HEADER_ALIGN // 声明所属段 -.section .multiboot_header +.section .text.boot multiboot_header: // 魔数 .long MULTIBOOT2_HEADER_MAGIC @@ -110,7 +120,7 @@ multiboot_header: multiboot_header_end: // 临时页表 4KB/页 -.section .data +.section .data.boot .align 0x1000 pml4: .skip 0x1000 @@ -166,10 +176,10 @@ gdt64_pointer64: .short gdt64_pointer-gdt64-1 .quad gdt64 -.section .text +.section .text.boot .global _start .type _start, @function -# 在 multiboot2.cpp 中定义 +// 在 multiboot2.cpp 中定义 .extern boot_info_addr .extern multiboot2_magic _start: @@ -231,8 +241,7 @@ _start: ret .code64 - -.section .text +.section .text.boot .global _start64 .type _start64, @function .extern kernel_main @@ -250,7 +259,7 @@ _start64: mov %rax, %gs mov %rax, %ss // 设置栈地址 - mov $STACK_TOP, %rsp + mov $stack_top, %rsp // 栈地址按照 4096 字节对齐 and $0xFFFFFFFFFFFFF000, %rsp // 帧指针修改为 0 @@ -261,7 +270,12 @@ _start64: hlt ret -.section .bss -STACK: - .skip 4096 * 4 -STACK_TOP: +// 声明所属段 +.section .bss.boot +// 16 字节对齐 +.align 16 +.global stack_top +// 栈 +stack_top: + // 跳过 16KB + .space 4096 * 4 diff --git a/src/arch/ia32/x86_64/gdt/gdt.cpp b/src/arch/ia32/x86_64/gdt/gdt.cpp index 636d928d1..487534388 100644 --- a/src/arch/ia32/x86_64/gdt/gdt.cpp +++ b/src/arch/ia32/x86_64/gdt/gdt.cpp @@ -14,58 +14,59 @@ * */ -#include "stdio.h" #include "gdt.h" +#include "cstdint" +#include "cstdio" namespace GDT { - // 加载 GDTR - extern "C" void gdt_load(uint32_t); - // 全局 gdt 指针 - static gdt_ptr64_t gdt_ptr64; - // 全局描述符表定义 - static gdt_entry_t gdt_entries[GDT_LENGTH] __attribute__((aligned(8))); +// 加载 GDTR +extern "C" void gdt_load(uint32_t); +// 全局 gdt 指针 +static gdt_ptr64_t gdt_ptr64; +// 全局描述符表定义 +static gdt_entry_t gdt_entries[GDT_LENGTH] __attribute__((aligned(8))); - void set_gdt(uint8_t _idx, uint32_t _base, uint32_t _limit, uint8_t _type, - uint8_t _s, uint8_t _dpl, uint8_t _p, uint8_t _avl, uint8_t _l, - uint8_t _db, uint8_t _g) { - gdt_entries[_idx].limit1 = (_limit & 0xFFFF); - gdt_entries[_idx].base_addr1 = (_base & 0xFFFF); - gdt_entries[_idx].base_addr2 = (_base >> 16) & 0xFF; - gdt_entries[_idx].type = _type; - gdt_entries[_idx].s = _s; - gdt_entries[_idx].dpl = _dpl; - gdt_entries[_idx].p = _p; - gdt_entries[_idx].limit2 = (_limit >> 16) & 0x0F; - gdt_entries[_idx].avl = _avl; - gdt_entries[_idx].l = _l; - gdt_entries[_idx].db = _db; - gdt_entries[_idx].g = _g; - gdt_entries[_idx].base_addr3 = (_base >> 24) & 0xFF; - return; - } +void set_gdt(uint8_t _idx, uint32_t _base, uint32_t _limit, uint8_t _type, + uint8_t _s, uint8_t _dpl, uint8_t _p, uint8_t _avl, uint8_t _l, + uint8_t _db, uint8_t _g) { + gdt_entries[_idx].limit1 = (_limit & 0xFFFF); + gdt_entries[_idx].base_addr1 = (_base & 0xFFFF); + gdt_entries[_idx].base_addr2 = (_base >> 16) & 0xFF; + gdt_entries[_idx].type = _type; + gdt_entries[_idx].s = _s; + gdt_entries[_idx].dpl = _dpl; + gdt_entries[_idx].p = _p; + gdt_entries[_idx].limit2 = (_limit >> 16) & 0x0F; + gdt_entries[_idx].avl = _avl; + gdt_entries[_idx].l = _l; + gdt_entries[_idx].db = _db; + gdt_entries[_idx].g = _g; + gdt_entries[_idx].base_addr3 = (_base >> 24) & 0xFF; + return; +} - int32_t init(void) { - // 全局描述符表界限 从 0 开始,所以总长要 - 1 - gdt_ptr64.limit = sizeof(gdt_entry_t) * GDT_LENGTH - 1; - gdt_ptr64.base = (uint64_t)&gdt_entries; - // 采用 Intel 平坦模型 - // Intel 文档要求首个描述符全 0 - set_gdt(GDT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); - // 内核指令段 - set_gdt(GDT_KERNEL_CODE, 0x0, 0x0, TYPE_CODE_EXECUTE_READ, S_CODE_DATA, - CPU::DPL0, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); - // 内核数据段 - set_gdt(GDT_KERNEL_DATA, 0x0, 0x0, TYPE_DATA_READ_WRITE, S_CODE_DATA, - CPU::DPL0, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); - // 用户模式代码段 - set_gdt(GDT_USER_CODE, 0x0, 0x0, TYPE_CODE_EXECUTE_READ, S_CODE_DATA, - CPU::DPL3, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); - // 用户模式数据段 - set_gdt(GDT_USER_DATA, 0x0, 0x0, TYPE_DATA_READ_WRITE, S_CODE_DATA, - CPU::DPL3, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); - // 加载全局描述符表地址到 GDTR 寄存器 - gdt_load((uint64_t)&gdt_ptr64); - info("gdt init.\n"); - return 0; - } -}; +int32_t init(void) { + // 全局描述符表界限 从 0 开始,所以总长要 - 1 + gdt_ptr64.limit = sizeof(gdt_entry_t) * GDT_LENGTH - 1; + gdt_ptr64.base = (uint64_t)&gdt_entries; + // 采用 Intel 平坦模型 + // Intel 文档要求首个描述符全 0 + set_gdt(GDT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); + // 内核指令段 + set_gdt(GDT_KERNEL_CODE, 0x0, 0x0, TYPE_CODE_EXECUTE_READ, S_CODE_DATA, + CPU::DPL0, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); + // 内核数据段 + set_gdt(GDT_KERNEL_DATA, 0x0, 0x0, TYPE_DATA_READ_WRITE, S_CODE_DATA, + CPU::DPL0, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); + // 用户模式代码段 + set_gdt(GDT_USER_CODE, 0x0, 0x0, TYPE_CODE_EXECUTE_READ, S_CODE_DATA, + CPU::DPL3, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); + // 用户模式数据段 + set_gdt(GDT_USER_DATA, 0x0, 0x0, TYPE_DATA_READ_WRITE, S_CODE_DATA, + CPU::DPL3, SEGMENT_PRESENT, 0x0, L_64BIT, 0x0, 0x0); + // 加载全局描述符表地址到 GDTR 寄存器 + gdt_load((uint64_t)&gdt_ptr64); + info("gdt init.\n"); + return 0; +} +}; // namespace GDT diff --git a/src/arch/ia32/x86_64/gdt/gdt_s.S b/src/arch/ia32/x86_64/gdt/gdt_s.S index 17e025f90..db91c40ce 100644 --- a/src/arch/ia32/x86_64/gdt/gdt_s.S +++ b/src/arch/ia32/x86_64/gdt/gdt_s.S @@ -4,6 +4,8 @@ // // gdt_s.S for Simple-XX/SimpleKernel. +// clang-format off + .code64 .section .text diff --git a/src/arch/ia32/x86_64/gdt/include/gdt.h b/src/arch/ia32/x86_64/gdt/include/gdt.h index bad327eab..3f7eb09fc 100644 --- a/src/arch/ia32/x86_64/gdt/include/gdt.h +++ b/src/arch/ia32/x86_64/gdt/include/gdt.h @@ -14,269 +14,268 @@ * */ -#ifndef _GDT_H_ -#define _GDT_H_ +#ifndef SIMPLEKERNEL_GDT_H +#define SIMPLEKERNEL_GDT_H -#include "stdint.h" #include "cpu.hpp" +#include "cstdint" /** * @brief GDT 接口 * @see 64-ia-32-architectures-software-developer-vol-3a-manual Chapter3 */ namespace GDT { - /// 全局描述符表长度 - static constexpr const uint32_t GDT_LENGTH = 5; - /// 各个内存段所在全局描述符表下标 - static constexpr const uint32_t GDT_NULL = 0; - /// 内核代码段 - static constexpr const uint32_t GDT_KERNEL_CODE = 1; - /// 内核数据段 - static constexpr const uint32_t GDT_KERNEL_DATA = 2; - /// 用户代码段 - static constexpr const uint32_t GDT_USER_CODE = 3; - /// 用户数据段 - static constexpr const uint32_t GDT_USER_DATA = 4; - /// 内核代码段选择子 0x08 - static constexpr const uint32_t SEG_KERNEL_CODE = GDT_KERNEL_CODE << 3; - /// 内核数据段选择子 - static constexpr const uint32_t SEG_KERNEL_DATA = GDT_KERNEL_DATA << 3; - /// 用户代码段选择子 - static constexpr const uint32_t SEG_USER_CODE = GDT_USER_CODE << 3; - /// 用户数据段选择子 - static constexpr const uint32_t SEG_USER_DATA = GDT_USER_DATA << 3; +/// 全局描述符表长度 +static constexpr const uint32_t GDT_LENGTH = 5; +/// 各个内存段所在全局描述符表下标 +static constexpr const uint32_t GDT_NULL = 0; +/// 内核代码段 +static constexpr const uint32_t GDT_KERNEL_CODE = 1; +/// 内核数据段 +static constexpr const uint32_t GDT_KERNEL_DATA = 2; +/// 用户代码段 +static constexpr const uint32_t GDT_USER_CODE = 3; +/// 用户数据段 +static constexpr const uint32_t GDT_USER_DATA = 4; +/// 内核代码段选择子 0x08 +static constexpr const uint32_t SEG_KERNEL_CODE = GDT_KERNEL_CODE << 3; +/// 内核数据段选择子 +static constexpr const uint32_t SEG_KERNEL_DATA = GDT_KERNEL_DATA << 3; +/// 用户代码段选择子 +static constexpr const uint32_t SEG_USER_CODE = GDT_USER_CODE << 3; +/// 用户数据段选择子 +static constexpr const uint32_t SEG_USER_DATA = GDT_USER_DATA << 3; - // type 类型 - // Code-and Data-Segment Types, S=1 - /// @see 64-ia-32-architectures-software-developer-vol-3a-manual#3.4.5.1 - /// 数据段 只读 - static constexpr const uint32_t TYPE_DATA_READ_ONLY = 0x00; - /// 数据段 只读,可访问 - static constexpr const uint32_t TYPE_DATA_READ_ONLY_ACCESSED = 0x01; - /// 数据段 读写 - static constexpr const uint32_t TYPE_DATA_READ_WRITE = 0x02; - /// 数据段,读写,可访问 - static constexpr const uint32_t TYPE_DATA_READ_WRITE_ACCESSED = 0x03; - /// 数据段,只读,? - static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN = 0x04; - /// 数据段,只读,?,可访问 - static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED = - 0x05; - /// 数据段,读写,? - static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN = 0x06; - /// 数据段,读写,?可访问 - static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED = - 0x07; +// type 类型 +// Code-and Data-Segment Types, S=1 +/// @see 64-ia-32-architectures-software-developer-vol-3a-manual#3.4.5.1 +/// 数据段 只读 +static constexpr const uint32_t TYPE_DATA_READ_ONLY = 0x00; +/// 数据段 只读,可访问 +static constexpr const uint32_t TYPE_DATA_READ_ONLY_ACCESSED = 0x01; +/// 数据段 读写 +static constexpr const uint32_t TYPE_DATA_READ_WRITE = 0x02; +/// 数据段,读写,可访问 +static constexpr const uint32_t TYPE_DATA_READ_WRITE_ACCESSED = 0x03; +/// 数据段,只读,? +static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN = 0x04; +/// 数据段,只读,?,可访问 +static constexpr const uint32_t TYPE_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED = 0x05; +/// 数据段,读写,? +static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN = 0x06; +/// 数据段,读写,?可访问 +static constexpr const uint32_t TYPE_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED + = 0x07; - /// 代码段,仅执行 - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY = 0x08; - /// 代码段,仅执行,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_ACCESSED = 0x09; - /// 代码段,可执行,可读 - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ = 0x0A; - /// 代码段,可执行,可读,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_ACCESSED = 0x0B; - /// 代码段,仅执行,? - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING = 0x0C; - /// 代码段,仅执行,?,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING_ACCESSED = - 0x0D; - /// 代码段,可执行,可读,? - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING = 0x0E; - /// 代码段,可执行,可读,?,可访问 - static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING_ACCESSED = - 0x0F; +/// 代码段,仅执行 +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY = 0x08; +/// 代码段,仅执行,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_ACCESSED = 0x09; +/// 代码段,可执行,可读 +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ = 0x0A; +/// 代码段,可执行,可读,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_ACCESSED = 0x0B; +/// 代码段,仅执行,? +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING = 0x0C; +/// 代码段,仅执行,?,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_ONLY_CONFORMING_ACCESSED + = 0x0D; +/// 代码段,可执行,可读,? +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING = 0x0E; +/// 代码段,可执行,可读,?,可访问 +static constexpr const uint32_t TYPE_CODE_EXECUTE_READ_CONFORMING_ACCESSED + = 0x0F; - // System-Segment and Gate-Descriptor Types, 32bit, when S=0 - /// @see 64-ia-32-architectures-software-developer-vol-3a-manual#3.5 - /// LDT - static constexpr const uint32_t TYPE_SYSTEM_LDT = 0x02; - // 64 位 TSS,可用 - static constexpr const uint32_t TYPE_SYSTEM_64_TSS_AVAILABLE = 0x09; - // 64 位 TSS,在用 - static constexpr const uint32_t TYPE_SYSTEM_64_TSS_BUSY = 0x0B; - // 64 位 调用门 - static constexpr const uint32_t TYPE_SYSTEM_64_CALL_GATE = 0x0C; - // 64 位 中断门 - static constexpr const uint32_t TYPE_SYSTEM_64_INTERRUPT_GATE = 0x0E; - // 64 位 陷阱门 - static constexpr const uint32_t TYPE_SYSTEM_64_TRAP_GATE = 0x0F; +// System-Segment and Gate-Descriptor Types, 32bit, when S=0 +/// @see 64-ia-32-architectures-software-developer-vol-3a-manual#3.5 +/// LDT +static constexpr const uint32_t TYPE_SYSTEM_LDT = 0x02; +// 64 位 TSS,可用 +static constexpr const uint32_t TYPE_SYSTEM_64_TSS_AVAILABLE = 0x09; +// 64 位 TSS,在用 +static constexpr const uint32_t TYPE_SYSTEM_64_TSS_BUSY = 0x0B; +// 64 位 调用门 +static constexpr const uint32_t TYPE_SYSTEM_64_CALL_GATE = 0x0C; +// 64 位 中断门 +static constexpr const uint32_t TYPE_SYSTEM_64_INTERRUPT_GATE = 0x0E; +// 64 位 陷阱门 +static constexpr const uint32_t TYPE_SYSTEM_64_TRAP_GATE = 0x0F; - // S 位 - /// 系统段 - static constexpr const uint32_t S_SYSTEM = 0x00; - /// 代码/数据段 - static constexpr const uint32_t S_CODE_DATA = 0x01; +// S 位 +/// 系统段 +static constexpr const uint32_t S_SYSTEM = 0x00; +/// 代码/数据段 +static constexpr const uint32_t S_CODE_DATA = 0x01; - // 各个段的全局描述符表的选择子 - /// 内核代码段 - static constexpr const uint32_t KERNEL_CS = SEG_KERNEL_CODE | CPU::DPL0; - /// 内核数据段 - static constexpr const uint32_t KERNEL_DS = SEG_KERNEL_DATA | CPU::DPL0; - /// 用户代码段 - static constexpr const uint32_t USER_CS = SEG_USER_CODE | CPU::DPL3; - /// 用户数据段 - static constexpr const uint32_t USER_DS = SEG_USER_DATA | CPU::DPL3; +// 各个段的全局描述符表的选择子 +/// 内核代码段 +static constexpr const uint32_t KERNEL_CS = SEG_KERNEL_CODE | CPU::DPL0; +/// 内核数据段 +static constexpr const uint32_t KERNEL_DS = SEG_KERNEL_DATA | CPU::DPL0; +/// 用户代码段 +static constexpr const uint32_t USER_CS = SEG_USER_CODE | CPU::DPL3; +/// 用户数据段 +static constexpr const uint32_t USER_DS = SEG_USER_DATA | CPU::DPL3; - // P 位 - /// 无效 - static constexpr const uint32_t SEGMENT_NOT_PRESENT = 0x00; - /// 有效 - static constexpr const uint32_t SEGMENT_PRESENT = 0x01; - // AVL - /// 无效 - static constexpr const uint32_t AVL_NOT_AVAILABLE = 0x00; - /// 有效 - static constexpr const uint32_t AVL_AVAILABLE = 0x01; - // L 位 - /// 32 位 - static constexpr const uint32_t L_32BIT = 0x00; - /// 64 位 - static constexpr const uint32_t L_64BIT = 0x01; - // D/B - /// @todo - static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_16 = 0x00; - /// @todo - static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_32 = 0x01; - /// @todo - static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_16 = 0x00; - /// @todo - static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_32 = 0x01; - /// @todo - static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_64KB = 0x00; - /// @todo - static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_4GB = 0x01; - // G - /// 字节粒度 - static constexpr const uint32_t G_BYTE = 0x00; - /// 4KB 粒度 - static constexpr const uint32_t G_4KB = 0x01; +// P 位 +/// 无效 +static constexpr const uint32_t SEGMENT_NOT_PRESENT = 0x00; +/// 有效 +static constexpr const uint32_t SEGMENT_PRESENT = 0x01; +// AVL +/// 无效 +static constexpr const uint32_t AVL_NOT_AVAILABLE = 0x00; +/// 有效 +static constexpr const uint32_t AVL_AVAILABLE = 0x01; +// L 位 +/// 32 位 +static constexpr const uint32_t L_32BIT = 0x00; +/// 64 位 +static constexpr const uint32_t L_64BIT = 0x01; +// D/B +/// @todo +static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_16 = 0x00; +/// @todo +static constexpr const uint32_t DB_EXECUTABLE_CODE_SEGMENT_32 = 0x01; +/// @todo +static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_16 = 0x00; +/// @todo +static constexpr const uint32_t DB_STACK_SEGMENT_STACK_POINTER_32 = 0x01; +/// @todo +static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_64KB = 0x00; +/// @todo +static constexpr const uint32_t DB_EXPAND_DOWN_DATA_SEGMENT_4GB = 0x01; +// G +/// 字节粒度 +static constexpr const uint32_t G_BYTE = 0x00; +/// 4KB 粒度 +static constexpr const uint32_t G_4KB = 0x01; - // 访问权限 - /// 内核读,执行 - static constexpr const uint32_t KREAD_EXEC = 0x9A; - /// 内核写 - static constexpr const uint32_t KREAD_WRITE = 0x92; - /// 用户读,执行 - static constexpr const uint32_t UREAD_EXEC = 0xFA; - /// 用户写 - static constexpr const uint32_t UREAD_WRITE = 0xF2; +// 访问权限 +/// 内核读,执行 +static constexpr const uint32_t KREAD_EXEC = 0x9A; +/// 内核写 +static constexpr const uint32_t KREAD_WRITE = 0x92; +/// 用户读,执行 +static constexpr const uint32_t UREAD_EXEC = 0xFA; +/// 用户写 +static constexpr const uint32_t UREAD_WRITE = 0xF2; - /// 段基址 - static constexpr const uint32_t BASE = 0x00; - /// 段长度 - static constexpr const uint32_t LIMIT = 0x00; +/// 段基址 +static constexpr const uint32_t BASE = 0x00; +/// 段长度 +static constexpr const uint32_t LIMIT = 0x00; - /** - * @brief 全局描述符 - */ - struct gdt_entry_t { - /// 段界限 15:00,long 模式下忽略 - uint64_t limit1 : 16; - /// 基址 15:00,long 模式下忽略 - uint64_t base_addr1 : 16; - /// 基址 23:16,long 模式下忽略 - uint64_t base_addr2 : 8; - /// 类型 - uint64_t type : 4; - /// Descriptor type (0 = system; 1 = code or data) - uint64_t s : 1; - /// Specifies the privilege level of the segment - uint64_t dpl : 2; - /// Indicates whether the segment is present in memory (set) or not - /// present (clear). - uint64_t p : 1; - /// 段界限 19:16,long 模式下忽略 - uint64_t limit2 : 4; - /// Available for use by system software - uint64_t avl : 1; - /// 64-bit code segment (IA-32e mode only) - uint64_t l : 1; - /// Default operation size(0 = 16 - bit segment; 1 = 32 - bit segment) - /// long 模式下忽略 - uint64_t db : 1; - /// Determines the scaling of the segment limit field. When the - /// granularity flag is clear, the segment limit is interpreted in - /// byte units; when flag is set, the segment limit is interpreted in - /// 4-KByte units. - /// long 模式下忽略 - uint64_t g : 1; - /// 基址 31:24,long 模式下忽略 - uint64_t base_addr3 : 8; - } __attribute__((packed)); +/** + * @brief 全局描述符 + */ +struct gdt_entry_t { + /// 段界限 15:00,long 模式下忽略 + uint64_t limit1 : 16; + /// 基址 15:00,long 模式下忽略 + uint64_t base_addr1 : 16; + /// 基址 23:16,long 模式下忽略 + uint64_t base_addr2 : 8; + /// 类型 + uint64_t type : 4; + /// Descriptor type (0 = system; 1 = code or data) + uint64_t s : 1; + /// Specifies the privilege level of the segment + uint64_t dpl : 2; + /// Indicates whether the segment is present in memory (set) or not + /// present (clear). + uint64_t p : 1; + /// 段界限 19:16,long 模式下忽略 + uint64_t limit2 : 4; + /// Available for use by system software + uint64_t avl : 1; + /// 64-bit code segment (IA-32e mode only) + uint64_t l : 1; + /// Default operation size(0 = 16 - bit segment; 1 = 32 - bit segment) + /// long 模式下忽略 + uint64_t db : 1; + /// Determines the scaling of the segment limit field. When the + /// granularity flag is clear, the segment limit is interpreted in + /// byte units; when flag is set, the segment limit is interpreted in + /// 4-KByte units. + /// long 模式下忽略 + uint64_t g : 1; + /// 基址 31:24,long 模式下忽略 + uint64_t base_addr3 : 8; +} __attribute__((packed)); - /** - * @brief 全剧描述符寄存器 - * @see 64-ia-32-architectures-software-developer-vol-3a-manual#3.5.1 - */ - struct gdt_ptr64_t { - // 全局描述符表限长 - uint16_t limit; - // 全局描述符表 64位 基地址 - uint64_t base; - } __attribute__((packed)); +/** + * @brief 全剧描述符寄存器 + * @see 64-ia-32-architectures-software-developer-vol-3a-manual#3.5.1 + */ +struct gdt_ptr64_t { + // 全局描述符表限长 + uint16_t limit; + // 全局描述符表 64位 基地址 + uint64_t base; +} __attribute__((packed)); - /** - * @brief 64 位 tss - * @see 64-ia-32-architectures-software-developer-vol-3a-manual#7.7 - * @see 64-ia-32-architectures-software-developer-vol-3a-manual#7.2.3 - * @note 目前没有使用 - */ - struct tss64_t { - uint32_t reserved0; - uint32_t rsp0_lower32; - uint32_t rsp0_upper32; - uint32_t rsp1_lower32; - uint32_t rsp1_upper32; - uint32_t rsp2_lower32; - uint32_t rsp2_upper32; - uint32_t reserved1; - uint32_t reserved2; - uint32_t ist1_lower32; - uint32_t ist1_upper32; - uint32_t ist2_lower32; - uint32_t ist2_upper32; - uint32_t ist3_lower32; - uint32_t ist3_upper32; - uint32_t ist4_lower32; - uint32_t ist4_upper32; - uint32_t ist5_lower32; - uint32_t ist5_upper32; - uint32_t ist6_lower32; - uint32_t ist6_upper32; - uint32_t ist7_lower32; - uint32_t ist7_upper32; - uint32_t reserved3; - uint32_t reserved4; - uint16_t reserved5; - uint16_t io_map_base_addr; - } __attribute__((packed)); +/** + * @brief 64 位 tss + * @see 64-ia-32-architectures-software-developer-vol-3a-manual#7.7 + * @see 64-ia-32-architectures-software-developer-vol-3a-manual#7.2.3 + * @note 目前没有使用 + */ +struct tss64_t { + uint32_t reserved0; + uint32_t rsp0_lower32; + uint32_t rsp0_upper32; + uint32_t rsp1_lower32; + uint32_t rsp1_upper32; + uint32_t rsp2_lower32; + uint32_t rsp2_upper32; + uint32_t reserved1; + uint32_t reserved2; + uint32_t ist1_lower32; + uint32_t ist1_upper32; + uint32_t ist2_lower32; + uint32_t ist2_upper32; + uint32_t ist3_lower32; + uint32_t ist3_upper32; + uint32_t ist4_lower32; + uint32_t ist4_upper32; + uint32_t ist5_lower32; + uint32_t ist5_upper32; + uint32_t ist6_lower32; + uint32_t ist6_upper32; + uint32_t ist7_lower32; + uint32_t ist7_upper32; + uint32_t reserved3; + uint32_t reserved4; + uint16_t reserved5; + uint16_t io_map_base_addr; +} __attribute__((packed)); - /** - * @brief 全局描述符表构造函数 - * @param _idx 描述符索引 - * @param _base 基址 - * @param _limit 长度 - * @param _type @todo - * @param _s @todo - * @param _dpl 权限 - * @param _p 有效 - * @param _avl @todo - * @param _l 32/64位 - * @param _db @todo - * @param _g 粒度 - */ - void set_gdt(uint8_t _idx, uint32_t _base, uint32_t _limit, uint8_t _type, - uint8_t _s, uint8_t _dpl, uint8_t _p, uint8_t _avl, uint8_t _l, - uint8_t _db, uint8_t _g); +/** + * @brief 全局描述符表构造函数 + * @param _idx 描述符索引 + * @param _base 基址 + * @param _limit 长度 + * @param _type @todo + * @param _s @todo + * @param _dpl 权限 + * @param _p 有效 + * @param _avl @todo + * @param _l 32/64位 + * @param _db @todo + * @param _g 粒度 + */ +void set_gdt(uint8_t _idx, uint32_t _base, uint32_t _limit, uint8_t _type, + uint8_t _s, uint8_t _dpl, uint8_t _p, uint8_t _avl, uint8_t _l, + uint8_t _db, uint8_t _g); - /** - * @brief 初始化 - * @return int32_t 成功返回 0 - * @todo 与 32 位合并 - * @todo 精简代码 - */ - int32_t init(void); -}; +/** + * @brief 初始化 + * @return int32_t 成功返回 0 + * @todo 与 32 位合并 + * @todo 精简代码 + */ +int32_t init(void); +}; // namespace GDT -#endif /* _GDT_H_ */ +#endif /* SIMPLEKERNEL_GDT_H */ diff --git a/src/arch/ia32/x86_64/intr/include/intr.h b/src/arch/ia32/x86_64/intr/include/intr.h index 7a7b91058..fd6b3c172 100644 --- a/src/arch/ia32/x86_64/intr/include/intr.h +++ b/src/arch/ia32/x86_64/intr/include/intr.h @@ -14,10 +14,10 @@ * */ -#ifndef _INTR_H_ -#define _INTR_H_ +#ifndef SIMPLEKERNEL_INTR_H +#define SIMPLEKERNEL_INTR_H -#include "stdint.h" +#include "cstdint" /// @todo 升级为 APIC class INTR { @@ -26,9 +26,9 @@ class INTR { * @brief 错误码结构 */ struct error_code_t { - uint32_t ext : 1; - uint32_t idt : 1; - uint32_t ti : 1; + uint32_t ext : 1; + uint32_t idt : 1; + uint32_t ti : 1; uint32_t sec_idx : 28; }; @@ -36,14 +36,14 @@ class INTR { * @brief 缺页错误码结构 */ struct page_fault_error_code_t { - uint32_t p : 1; - uint32_t wr : 1; - uint32_t us : 1; - uint32_t rsvd : 1; - uint32_t id : 1; - uint32_t pk : 1; + uint32_t p : 1; + uint32_t wr : 1; + uint32_t us : 1; + uint32_t rsvd : 1; + uint32_t id : 1; + uint32_t pk : 1; uint32_t reserved1 : 9; - uint32_t sgx : 1; + uint32_t sgx : 1; uint32_t reserved2 : 16; }; @@ -75,23 +75,23 @@ class INTR { }; // 定义中断处理函数指针 - typedef void (*interrupt_handler_t)(intr_context_t *); + typedef void (*interrupt_handler_t)(intr_context_t*); private: /// 中断表最大值 - static constexpr const uint32_t INTERRUPT_MAX = 256; + static constexpr const uint32_t INTERRUPT_MAX = 256; /// 8259A 相关定义 /// Master (IRQs 0-7) - static constexpr const uint32_t IO_PIC1 = 0x20; + static constexpr const uint32_t IO_PIC1 = 0x20; /// Slave (IRQs 8-15) - static constexpr const uint32_t IO_PIC2 = 0xA0; - static constexpr const uint32_t IO_PIC1C = IO_PIC1 + 1; - static constexpr const uint32_t IO_PIC2C = IO_PIC2 + 1; + static constexpr const uint32_t IO_PIC2 = 0xA0; + static constexpr const uint32_t IO_PIC1C = IO_PIC1 + 1; + static constexpr const uint32_t IO_PIC2C = IO_PIC2 + 1; /// End-of-interrupt command code - static constexpr const uint32_t PIC_EOI = 0x20; + static constexpr const uint32_t PIC_EOI = 0x20; /// 中断名数组 - static constexpr const char *const intrnames[] = { + static constexpr const char* const intrnames[] = { "Divide Error", "Debug Exception", "NMI Interrupt", @@ -121,26 +121,26 @@ class INTR { */ struct idt_entry64_t { // 低位地址 - uint64_t offset0 : 16; + uint64_t offset0 : 16; // 选择子 uint64_t selector : 16; // 中断栈表 // 64-ia-32-architectures-software-developer-vol-3a-manual#6.14.5 - uint64_t ist : 3; + uint64_t ist : 3; // 填充 0 - uint64_t zero0 : 5; + uint64_t zero0 : 5; // 类型 - uint64_t type : 4; + uint64_t type : 4; // 填充 0 - uint64_t zero1 : 1; + uint64_t zero1 : 1; // 权限 - uint64_t dpl : 2; + uint64_t dpl : 2; // 存在位 - uint64_t p : 1; + uint64_t p : 1; // 中段地址 - uint64_t offset1 : 16; + uint64_t offset1 : 16; // 高位地址 - uint64_t offset2 : 32; + uint64_t offset2 : 32; // 保留 uint64_t reserved : 32; } __attribute__((packed)); @@ -158,10 +158,10 @@ class INTR { /// 中断处理函数指针数组 static interrupt_handler_t interrupt_handlers[INTERRUPT_MAX] - __attribute__((aligned(4))); + __attribute__((aligned(4))); /// 中断描述符表 static idt_entry64_t idt_entry64[INTERRUPT_MAX] - __attribute__((aligned(16))); + __attribute__((aligned(16))); /// IDTR static idt_ptr_t idt_ptr; @@ -175,24 +175,24 @@ class INTR { * @param _dpl ? * @param _p ? */ - void set_idt(uint8_t _num, uintptr_t _base, uint16_t _selector, - uint8_t _ist, uint8_t _type, uint8_t _dpl, uint8_t _p); + void set_idt(uint8_t _num, uintptr_t _base, uint16_t _selector, + uint8_t _ist, uint8_t _type, uint8_t _dpl, uint8_t _p); /** * @brief 8259A 芯片初始化 */ - void init_interrupt_chip(void); + void init_interrupt_chip(void); /** * @brief 重设 8259A 芯片 * @param _no 要重设的中断号 */ - void clear_interrupt_chip(uint8_t _no); + void clear_interrupt_chip(uint8_t _no); /** * @brief 关闭 8259A 芯片的所有中断,为启动 APIC 作准备 */ - void disable_interrupt_chip(void); + void disable_interrupt_chip(void); public: // External(hardware generated) interrupts. @@ -213,60 +213,60 @@ class INTR { static constexpr const uint32_t INT_GENERAL_PROTECT = 13; static constexpr const uint32_t INT_PAGE_FAULT = 14; // 15 没有使用 - static constexpr const uint32_t INT_X87_FPU = 16; - static constexpr const uint32_t INT_ALIGNMENT = 17; - static constexpr const uint32_t INT_MACHINE_CHECK = 18; - static constexpr const uint32_t INT_SIMD_FLOAT = 19; - static constexpr const uint32_t INT_VIRTUAL_EXCE = 20; + static constexpr const uint32_t INT_X87_FPU = 16; + static constexpr const uint32_t INT_ALIGNMENT = 17; + static constexpr const uint32_t INT_MACHINE_CHECK = 18; + static constexpr const uint32_t INT_SIMD_FLOAT = 19; + static constexpr const uint32_t INT_VIRTUAL_EXCE = 20; // 21~31 保留 // 定义IRQ // 电脑系统计时器 - static constexpr const uint32_t IRQ0 = 32; + static constexpr const uint32_t IRQ0 = 32; // 键盘 - static constexpr const uint32_t IRQ1 = 33; + static constexpr const uint32_t IRQ1 = 33; // 与 IRQ9 相接,MPU-401 MD 使用 - static constexpr const uint32_t IRQ2 = 34; + static constexpr const uint32_t IRQ2 = 34; // 串口设备 - static constexpr const uint32_t IRQ3 = 35; + static constexpr const uint32_t IRQ3 = 35; // 串口设备 - static constexpr const uint32_t IRQ4 = 36; + static constexpr const uint32_t IRQ4 = 36; // 建议声卡使用 - static constexpr const uint32_t IRQ5 = 37; + static constexpr const uint32_t IRQ5 = 37; // 软驱传输控制使用 - static constexpr const uint32_t IRQ6 = 38; + static constexpr const uint32_t IRQ6 = 38; // 打印机传输控制使用 - static constexpr const uint32_t IRQ7 = 39; + static constexpr const uint32_t IRQ7 = 39; // 即时时钟 - static constexpr const uint32_t IRQ8 = 40; + static constexpr const uint32_t IRQ8 = 40; // 与 IRQ2 相接,可设定给其他硬件 - static constexpr const uint32_t IRQ9 = 41; + static constexpr const uint32_t IRQ9 = 41; // 建议网卡使用 - static constexpr const uint32_t IRQ10 = 42; + static constexpr const uint32_t IRQ10 = 42; // 建议 AGP 显卡使用 - static constexpr const uint32_t IRQ11 = 43; + static constexpr const uint32_t IRQ11 = 43; // 接 PS/2 鼠标,也可设定给其他硬件 - static constexpr const uint32_t IRQ12 = 44; + static constexpr const uint32_t IRQ12 = 44; // 协处理器使用 - static constexpr const uint32_t IRQ13 = 45; + static constexpr const uint32_t IRQ13 = 45; // SATA 主硬盘 - static constexpr const uint32_t IRQ14 = 46; + static constexpr const uint32_t IRQ14 = 46; // SATA 从硬盘 - static constexpr const uint32_t IRQ15 = 47; + static constexpr const uint32_t IRQ15 = 47; // 系统调用 - static constexpr const uint32_t IRQ128 = 128; + static constexpr const uint32_t IRQ128 = 128; /** * @brief 获取单例 * @return INTR& 静态对象 */ - static INTR &get_instance(void); + static INTR& get_instance(void); /** * @brief 中断初始化 * @return int32_t desc */ - int32_t init(void); + int32_t init(void); /** * @brief 执行中断 @@ -274,9 +274,9 @@ class INTR { * @param _intr_context 上下文 * @return int32_t 保存中断处理后的返回值 */ - int32_t call_irq(uint8_t _no, intr_context_t *_intr_context); + int32_t call_irq(uint8_t _no, intr_context_t* _intr_context); - int32_t call_isr(uint8_t _no, intr_context_t *_intr_context); + int32_t call_isr(uint8_t _no, intr_context_t* _intr_context); /** * @brief 注册一个中断处理函数 @@ -302,7 +302,7 @@ class INTR { * @param _no 中断号 * @return const char* 对应的中断名 */ - const char *get_intr_name(uint8_t _no); + const char* get_intr_name(uint8_t _no); }; /** @@ -314,12 +314,12 @@ class TIMER { * @brief 获取单例 * @return TIMER& 静态对象 */ - static TIMER &get_instance(void); + static TIMER& get_instance(void); /** * @brief 初始化 */ - void init(void); + void init(void); }; -#endif /* _INTR_H_ */ +#endif /* SIMPLEKERNEL_INTR_H */ diff --git a/src/arch/ia32/x86_64/intr/intr.cpp b/src/arch/ia32/x86_64/intr/intr.cpp index 27f53ba67..f3b33a4be 100644 --- a/src/arch/ia32/x86_64/intr/intr.cpp +++ b/src/arch/ia32/x86_64/intr/intr.cpp @@ -15,12 +15,12 @@ * */ -#include "io.h" -#include "cpu.hpp" -#include "stdio.h" -#include "gdt.h" #include "intr.h" #include "apic.h" +#include "cpu.hpp" +#include "cstdio" +#include "gdt.h" +#include "io.h" #include "keyboard.h" // 声明中断处理函数 0 ~ 19 属于 CPU 的异常中断 @@ -109,7 +109,7 @@ extern "C" void idt_load(uint32_t); /** * @brief IRQ 处理函数 */ -extern "C" void irq_handler(uint8_t _no, INTR::intr_context_t *_intr_context) { +extern "C" void irq_handler(uint8_t _no, INTR::intr_context_t* _intr_context) { INTR::get_instance().call_irq(_no, _intr_context); return; } @@ -117,15 +117,15 @@ extern "C" void irq_handler(uint8_t _no, INTR::intr_context_t *_intr_context) { /** * @brief ISR 处理函数 */ -extern "C" void isr_handler(uint8_t _no, INTR::intr_context_t *_intr_context, - INTR::error_code_t *_err_code) { +extern "C" void isr_handler(uint8_t _no, INTR::intr_context_t* _intr_context, + INTR::error_code_t* _err_code) { (void)_err_code; INTR::get_instance().call_isr(_no, _intr_context); return; } // 默认处理函数 -static void handler_default(INTR::intr_context_t *) { +static void handler_default(INTR::intr_context_t*) { while (1) { ; } @@ -135,9 +135,9 @@ static void handler_default(INTR::intr_context_t *) { // 中断处理函数指针数组 INTR::interrupt_handler_t INTR::interrupt_handlers[INTERRUPT_MAX]; // 中断描述符表 -INTR::idt_entry64_t INTR::idt_entry64[INTERRUPT_MAX]; +INTR::idt_entry64_t INTR::idt_entry64[INTERRUPT_MAX]; // IDTR -INTR::idt_ptr_t INTR::idt_ptr; +INTR::idt_ptr_t INTR::idt_ptr; // 64-ia-32-architectures-software-developer-vol-3a-manual#6.14.1 void INTR::set_idt(uint8_t _num, uintptr_t _base, uint16_t _selector, @@ -209,7 +209,7 @@ void INTR::disable_interrupt_chip(void) { return; } -INTR &INTR::get_instance(void) { +INTR& INTR::get_instance(void) { /// 定义全局 INTR 对象 static INTR intr; return intr; @@ -358,7 +358,7 @@ int32_t INTR::init(void) { return 0; } -int32_t INTR::call_irq(uint8_t _no, intr_context_t *_intr_context) { +int32_t INTR::call_irq(uint8_t _no, intr_context_t* _intr_context) { // 重设PIC芯片 clear_interrupt_chip(_no); if (interrupt_handlers[_no] != nullptr) { @@ -367,7 +367,7 @@ int32_t INTR::call_irq(uint8_t _no, intr_context_t *_intr_context) { return 0; } -int32_t INTR::call_isr(uint8_t _no, intr_context_t *_intr_context) { +int32_t INTR::call_isr(uint8_t _no, intr_context_t* _intr_context) { if (interrupt_handlers[_no] != nullptr) { interrupt_handlers[_no](_intr_context); } @@ -412,8 +412,8 @@ void INTR::disable_irq(uint8_t _no) { return; } -const char *INTR::get_intr_name(uint8_t _no) { - if (_no < sizeof(intrnames) / sizeof(const char *const)) { +const char* INTR::get_intr_name(uint8_t _no) { + if (_no < sizeof(intrnames) / sizeof(const char* const)) { return intrnames[_no]; } return "(unknown trap)"; diff --git a/src/arch/ia32/x86_64/intr/intr_s.S b/src/arch/ia32/x86_64/intr/intr_s.S index aec27c7da..3bf7f1344 100644 --- a/src/arch/ia32/x86_64/intr/intr_s.S +++ b/src/arch/ia32/x86_64/intr/intr_s.S @@ -1,8 +1,11 @@ -// This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +// This file is a part of Simple-XX/SimpleKernel +// (https://github.com/Simple-XX/SimpleKernel). # // intr_s.s for Simple-XX/SimpleKernel. +// clang-format off + .code64 // 加载 idt diff --git a/src/arch/ia32/x86_64/intr/timer.cpp b/src/arch/ia32/x86_64/intr/timer.cpp index 1fff2cc79..e5a0b8aa1 100644 --- a/src/arch/ia32/x86_64/intr/timer.cpp +++ b/src/arch/ia32/x86_64/intr/timer.cpp @@ -14,21 +14,18 @@ * */ -#include "stdint.h" -#include "stdio.h" -#include "cpu.hpp" +#include "cstdio" #include "intr.h" -#include "io.h" /** * @brief 时钟中断 */ -void timer_intr(INTR::intr_context_t *) { +void timer_intr(INTR::intr_context_t*) { printf("timer.\n"); return; } -TIMER &TIMER::get_instance(void) { +TIMER& TIMER::get_instance(void) { /// 定义全局 TIMER 对象 static TIMER timer; return timer; diff --git a/src/arch/ia32/x86_64/link.ld b/src/arch/ia32/x86_64/link.ld index dea73f61b..fecae84ec 100644 --- a/src/arch/ia32/x86_64/link.ld +++ b/src/arch/ia32/x86_64/link.ld @@ -2,75 +2,244 @@ /* This file is a part of Simple-XX/SimpleKernel * (https://github.com/Simple-XX/SimpleKernel). * - * link.ld for Simple-XX/SimpleKernel. - * 链接脚本,指定生成的二进制文件的布局 */ + * link.ld for Simple-XX/SimpleKernel. + * 链接脚本,指定生成的二进制文件的布局 + */ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2022 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ /* 指定输出格式 */ -OUTPUT_FORMAT(elf64-x86-64) -/* 执行输出架构 */ +OUTPUT_FORMAT( + "elf64-x86-64", + "elf64-x86-64", + "elf64-x86-64" +) +/* 指定输出架构 */ OUTPUT_ARCH(i386:x86-64) /* 设置入口点 */ ENTRY(_start) /* 设置各个 section */ SECTIONS { - . = 0; - - PROVIDE(kernel_start = .); - /* 指定内核从地址 1M 处开始 */ - /* 0~1M 的空间为 BIOS 保留区域 */ - /* TODO: 这里似乎可以修改为任意地址 */ - . = 1M; - - PROVIDE(kernel_text_start = .); - /* 代码段 */ - .text : ALIGN(4K) { - *(.multiboot_header) - *(.text*) + PROVIDE (__executable_start = SEGMENT_START("text-segment", 1M)); + . = SEGMENT_START("text-segment", 1M); + .boot : { *(.text.boot) *(.data.boot) *(.bss.boot) } + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - PROVIDE(kernel_text_end = .); - - PROVIDE(kernel_rodata_start = .); - /* 只读数据段 */ - .rodata : ALIGN(4K) { - /* 构造函数起点 */ - PROVIDE(ctors_start = .); - *(SORT_BY_INIT_PRIORITY (.init_array.*)) - *(SORT_BY_INIT_PRIORITY (.ctors.*)) - *(.init_array .ctors) - /* 构造函数终点 */ - PROVIDE(ctors_end = .); - /* 析构函数起点 */ - PROVIDE(dtors_start = .); - *(.dtor*) - /* 析构函数终点 */ - PROVIDE(dtors_end = .); - *(.rodata*) - *(.gcc_except_table) - } - PROVIDE(kernel_rodata_end = .); - - PROVIDE(kernel_data_start = .); - /* 数据段 */ - .data : ALIGN(4K) { - *(.data*) - *(.eh_frame) - *(.got*) - } - PROVIDE(kernel_data_end = .); - - PROVIDE(kernel_bss_start = .); - /* 未初始化数据段 */ - .bss : ALIGN(4K) { - *(.bss); + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } - PROVIDE(kernel_bss_end = .); - - PROVIDE(kernel_debug_start = .); - /* 调试信息 */ - .debug : ALIGN(4K) { - *(.debug*) + .relr.dyn : { *(.relr.dyn) } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : { + KEEP (*(SORT_NONE(.init))) } - PROVIDE(kernel_debug_end = .); - - PROVIDE(kernel_end = .); + .plt : { *(.plt) *(.iplt) } + .plt.got : { *(.plt.got) } + .plt.sec : { *(.plt.sec) } + .text : { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1. */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions. */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2. */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2. */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions. */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3. */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF 5. */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + .debug_sup 0 : { *(.debug_sup) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } diff --git a/src/arch/riscv64/boot/boot.S b/src/arch/riscv64/boot/boot.S index 62509c3d7..be76a1113 100644 --- a/src/arch/riscv64/boot/boot.S +++ b/src/arch/riscv64/boot/boot.S @@ -1,12 +1,23 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// boot.S for Simple-XX/SimpleKernel. -// 启动代码,进行一些设置后跳转到 kernel_main +/** + * @file boot.S + * @brief 启动代码,进行一些设置后跳转到 kernel_main + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-01-01 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-01-01MRNIU迁移到 doxygen + *
+ */ -.section .init -.globl _start +// clang-format off + +.section .text.boot +.global _start .type _start, @function .extern kernel_main .extern cpp_init @@ -24,9 +35,11 @@ _start: call cpp_init // 跳转到 C 代码执行 call kernel_main +loop: + j loop // 声明所属段 -.section .bss +.section .bss.boot // 16 字节对齐 .align 16 .global stack_top diff --git a/src/arch/riscv64/context.S b/src/arch/riscv64/context.S new file mode 100644 index 000000000..e1902d2eb --- /dev/null +++ b/src/arch/riscv64/context.S @@ -0,0 +1,218 @@ + +/** + * @file context.S + * @brief 上下文保存 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-01-01 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-01-01MRNIU迁移到 doxygen + *
+ */ + +// clang-format off + +// 寄存器长度,8 字节 +.equ REG_BYTES, 8 +// 所有寄存器数量 +.equ ALL_REGS, 71 +// 保存所有寄存器需要的大小 +.equ ALL_SIZE, (ALL_REGS * REG_BYTES) + +// 将寄存器 a 保存在 c 偏移 b 的位置 +.macro sd_base a, b, c +sd \a, ((\b) * REG_BYTES)(\c) +.endm + +// 从 c 的偏移 b 处获取数据并赋值给寄存器 a +.macro ld_base a, b, c +ld \a, ((\b) * REG_BYTES)(\c) +.endm + +// 将 float 寄存器 a 保存在 c 偏移 b 的位置 +.macro fsd_base a, b, c +fsd \a, ((\b) * REG_BYTES)(\c) +.endm + +// 从 c 的偏移 b 处获取数据并赋值给 float 寄存器 a +.macro fld_base a, b, c +fld \a, ((\b) * REG_BYTES)(\c) +.endm + +/** + * @brief 保存所有寄存器 + * @param _base 要保存到的基地址 + */ +.macro all_regs_save _base + sd_base zero, 0, \_base + sd_base ra, 1, \_base + sd_base sp, 2, \_base + sd_base gp, 3, \_base + sd_base tp, 4, \_base + sd_base t0, 5, \_base + sd_base t1, 6, \_base + sd_base t2, 7, \_base + sd_base s0, 8, \_base + sd_base s1, 9, \_base + sd_base a0, 10, \_base + sd_base a1, 11, \_base + sd_base a2, 12, \_base + sd_base a3, 13, \_base + sd_base a4, 14, \_base + sd_base a5, 15, \_base + sd_base a6, 16, \_base + sd_base a7, 17, \_base + sd_base s2, 18, \_base + sd_base s3, 19, \_base + sd_base s4, 20, \_base + sd_base s5, 21, \_base + sd_base s6, 22, \_base + sd_base s7, 23, \_base + sd_base s8, 24, \_base + sd_base s9, 25, \_base + sd_base s10, 26, \_base + sd_base s11, 27, \_base + sd_base t3, 28, \_base + sd_base t4, 29, \_base + sd_base t5, 30, \_base + sd_base t6, 31, \_base + + fsd_base ft0, 32, \_base + fsd_base ft1, 33, \_base + fsd_base ft2, 34, \_base + fsd_base ft3, 35, \_base + fsd_base ft4, 36, \_base + fsd_base ft5, 37, \_base + fsd_base ft6, 38, \_base + fsd_base ft7, 39, \_base + fsd_base fs0, 40, \_base + fsd_base fs1, 41, \_base + fsd_base fa0, 42, \_base + fsd_base fa1, 43, \_base + fsd_base fa2, 44, \_base + fsd_base fa3, 45, \_base + fsd_base fa4, 46, \_base + fsd_base fa5, 47, \_base + fsd_base fa6, 48, \_base + fsd_base fa7, 49, \_base + fsd_base fs2, 50, \_base + fsd_base fs3, 51, \_base + fsd_base fs4, 52, \_base + fsd_base fs5, 53, \_base + fsd_base fs6, 54, \_base + fsd_base fs7, 55, \_base + fsd_base fs8, 56, \_base + fsd_base fs9, 57, \_base + fsd_base fs10, 58, \_base + fsd_base fs11, 59, \_base + fsd_base ft8, 60, \_base + fsd_base ft9, 61, \_base + fsd_base ft10, 62, \_base + fsd_base ft11, 63, \_base + + csrr t0, sepc + sd_base t0, 64, \_base + csrr t0, stval + sd_base t0, 65, \_base + csrr t0, scause + sd_base t0, 66, \_base + csrr t0, sie + sd_base t0, 67, \_base + csrr t0, sstatus + sd_base t0, 68, \_base + csrr t0, satp + sd_base t0, 69, \_base + csrr t0, sscratch + sd_base t0, 70, \_base +.endm + +/** + * @brief 恢复所有寄存器 + * @param _base 要恢复数据的基地址 + */ +.macro all_regs_load _base + ld_base t0, 64, \_base + csrw sepc, t0 + ld_base t0, 65, \_base + csrw stval, t0 + ld_base t0, 66, \_base + csrw scause, t0 + ld_base t0, 67, \_base + csrw sie, t0 + ld_base t0, 68, \_base + csrw sstatus, t0 + ld_base t0, 69, \_base + csrw satp, t0 + ld_base t0, 70, \_base + csrw sscratch, t0 + + ld_base zero, 0, \_base + ld_base ra, 1, \_base + ld_base sp, 2, \_base + ld_base gp, 3, \_base + ld_base tp, 4, \_base + ld_base t0, 5, \_base + ld_base t1, 6, \_base + ld_base t2, 7, \_base + ld_base s0, 8, \_base + ld_base s1, 9, \_base + ld_base a0, 10, \_base + ld_base a1, 11, \_base + ld_base a2, 12, \_base + ld_base a3, 13, \_base + ld_base a4, 14, \_base + ld_base a5, 15, \_base + ld_base a6, 16, \_base + ld_base a7, 17, \_base + ld_base s2, 18, \_base + ld_base s3, 19, \_base + ld_base s4, 20, \_base + ld_base s5, 21, \_base + ld_base s6, 22, \_base + ld_base s7, 23, \_base + ld_base s8, 24, \_base + ld_base s9, 25, \_base + ld_base s10, 26, \_base + ld_base s11, 27, \_base + ld_base t3, 28, \_base + ld_base t4, 29, \_base + ld_base t5, 30, \_base + ld_base t6, 31, \_base + + fld_base ft0, 32, \_base + fld_base ft1, 33, \_base + fld_base ft2, 34, \_base + fld_base ft3, 35, \_base + fld_base ft4, 36, \_base + fld_base ft5, 37, \_base + fld_base ft6, 38, \_base + fld_base ft7, 39, \_base + fld_base fs0, 40, \_base + fld_base fs1, 41, \_base + fld_base fa0, 42, \_base + fld_base fa1, 43, \_base + fld_base fa2, 44, \_base + fld_base fa3, 45, \_base + fld_base fa4, 46, \_base + fld_base fa5, 47, \_base + fld_base fa6, 48, \_base + fld_base fa7, 49, \_base + fld_base fs2, 50, \_base + fld_base fs3, 51, \_base + fld_base fs4, 52, \_base + fld_base fs5, 53, \_base + fld_base fs6, 54, \_base + fld_base fs7, 55, \_base + fld_base fs8, 56, \_base + fld_base fs9, 57, \_base + fld_base fs10, 58, \_base + fld_base fs11, 59, \_base + fld_base ft8, 60, \_base + fld_base ft9, 61, \_base + fld_base ft10, 62, \_base + fld_base ft11, 63, \_base +.endm diff --git a/src/arch/riscv64/cpu.hpp b/src/arch/riscv64/cpu.hpp index 71f20e76e..896f4ee82 100644 --- a/src/arch/riscv64/cpu.hpp +++ b/src/arch/riscv64/cpu.hpp @@ -14,37 +14,304 @@ * */ -#ifndef _CPU_HPP_ -#define _CPU_HPP_ +#ifndef SIMPLEKERNEL_CPU_HPP +#define SIMPLEKERNEL_CPU_HPP -#include "stdio.h" -#include "stdint.h" -#include "stdbool.h" +#include "cstdbool" +#include "cstdint" +#include "cstdio" +#include "iostream" /** * @brief cpu 相关 * @todo */ namespace CPU { +/** + * @brief pte 结构 + * @todo 使用 pte 结构重写 vmm + */ +struct pte_t { + enum { + VALID_OFFSET = 0, + READ_OFFSET = 1, + WRITE_OFFSET = 2, + EXEC_OFFSET = 3, + USER_OFFSET = 4, + GLOBAL_OFFSET = 5, + ACCESSED_OFFSET = 6, + DIRTY_OFFSET = 7, + VALID = 1 << VALID_OFFSET, + READ = 1 << READ_OFFSET, + WRITE = 1 << WRITE_OFFSET, + EXEC = 1 << EXEC_OFFSET, + USER = 1 << USER_OFFSET, + GLOBAL = 1 << GLOBAL_OFFSET, + ACCESSED = 1 << ACCESSED_OFFSET, + DIRTY = 1 << DIRTY_OFFSET, + }; + + union { + struct { + uint64_t flags : 8; + uint64_t rsw : 2; + uint64_t ppn : 44; + uint64_t reserved : 10; + }; + + uint64_t val; + }; + + pte_t(void) { + val = 0; + return; + } + + pte_t(uint64_t _val) : val(_val) { + return; + } + + friend std::ostream& operator<<(std::ostream& _os, const pte_t& _pte) { + printf("val: 0x%p, valid: %s, read: %s, write: %s, exec: %s, user: %s, " + "global: %s, accessed: %s, dirty: %s, rsw: 0x%p, ppn: 0x%p", + _pte.val, (_pte.flags & VALID) == VALID ? "true" : "false", + (_pte.flags & READ) == READ ? "true" : "false", + (_pte.flags & WRITE) == WRITE ? "true" : "false", + (_pte.flags & EXEC) == EXEC ? "true" : "false", + (_pte.flags & USER) == USER ? "true" : "false", + (_pte.flags & GLOBAL) == GLOBAL ? "true" : "false", + (_pte.flags & ACCESSED) == ACCESSED ? "true" : "false", + (_pte.flags & DIRTY) == DIRTY ? "true" : "false", _pte.rsw, + _pte.ppn); + return _os; + } +}; + +/** + * @brief satp 结构 + */ +struct satp_t { + enum { + NONE = 0, + SV39 = 8, + SV48 = 9, + SV57 = 10, + SV64 = 11, + }; + + static constexpr const char* MODE_NAME[] = { + [NONE] = "NONE", "UNKNOWN", "UNKNOWN", "UNKNOWN", + "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", + [SV39] = "SV39", [SV48] = "SV48", [SV57] = "SV57", [SV64] = "SV64", + }; + + union { + struct { + uint64_t ppn : 44; + uint64_t asid : 16; + uint64_t mode : 4; + }; + + uint64_t val; + }; + + static constexpr const uint64_t PPN_OFFSET = 12; + + satp_t(void) { + val = 0; + return; + } + + satp_t(uint64_t _val) : val(_val) { + return; + } + + friend std::ostream& operator<<(std::ostream& _os, const satp_t& _satp) { + printf("val: 0x%p, ppn: 0x%p, asid: 0x%p, mode: %s", _satp.val, + _satp.ppn, _satp.asid, MODE_NAME[_satp.mode]); + return _os; + } +}; + +/// 机器模式定义 +enum { + U_MODE = 0, + S_MODE = 1, + M_MODE = 3, +}; + +enum { + INTR_SOFT = 0, + /// U 态软中断 + INTR_SOFT_U = INTR_SOFT + U_MODE, + /// S 态软中断 + INTR_SOFT_S = INTR_SOFT + S_MODE, + /// M 态软中断 + INTR_SOFT_M = INTR_SOFT + M_MODE, + INTR_TIMER = 4, + /// U 态时钟中断 + INTR_TIMER_U = INTR_TIMER + U_MODE, + /// S 态时钟中断 + INTR_TIMER_S = INTR_TIMER + S_MODE, + /// M 态时钟中断 + INTR_TIMER_M = INTR_TIMER + M_MODE, + INTR_EXTERN = 8, + /// U 态外部中断 + INTR_EXTERN_U = INTR_EXTERN + U_MODE, + /// S 态外部中断 + INTR_EXTERN_S = INTR_EXTERN + S_MODE, + /// M 态外部中断 + INTR_EXTERN_M = INTR_EXTERN + M_MODE, +}; + +enum { + EXCP_INSTRUCTION_ADDRESS_MISALIGNED = 0, + EXCP_INSTRUCTION_ACCESS_FAULT = 1, + EXCP_ILLEGAL_INSTRUCTION = 2, + EXCP_BREAKPOINT = 3, + EXCP_LOAD_ADDRESS_MISALIGNED = 4, + EXCP_LOAD_ACCESS_FAULT = 5, + EXCP_STORE_AMO_ADDRESS_MISALIGNED = 6, + EXCP_STORE_AMO_ACCESS_FAULT = 7, + EXCP_ECALL = 8, + EXCP_ECALL_U = EXCP_ECALL + U_MODE, + EXCP_ECALL_S = EXCP_ECALL + S_MODE, + EXCP_ECALL_M = EXCP_ECALL + M_MODE, + EXCP_INSTRUCTION_PAGE_FAULT = 12, + EXCP_LOAD_PAGE_FAULT = 13, + EXCP_STORE_AMO_PAGE_FAULT = 15, +}; + // Supervisor Status Register, sstatus // User Interrupt Enable -static constexpr const uint64_t SSTATUS_UIE = 1 << 0; +static constexpr const uint64_t SSTATUS_UIE = 1 << 0; // Supervisor Interrupt Enable -static constexpr const uint64_t SSTATUS_SIE = 1 << 1; +static constexpr const uint64_t SSTATUS_SIE = 1 << 1; // User Previous Interrupt Enable static constexpr const uint64_t SSTATUS_UPIE = 1 << 4; // Supervisor Previous Interrupt Enable static constexpr const uint64_t SSTATUS_SPIE = 1 << 5; // Previous mode, 1=Supervisor, 0=User -static constexpr const uint64_t SSTATUS_SPP = 1 << 8; +static constexpr const uint64_t SSTATUS_SPP = 1 << 8; + +/** + * @brief mstatus 寄存器定义 + */ +struct mstatus_t { + union { + struct { + // interrupt enable + uint64_t ie : 4; + // previous interrupt enable + uint64_t pie : 4; + // previous mode (supervisor) + uint64_t spp : 1; + uint64_t unused1 : 2; + // previous mode (machine) + uint64_t mpp : 2; + // FPU status + uint64_t fs : 2; + // extensions status + uint64_t xs : 2; + // modify privilege + uint64_t mprv : 1; + // permit supervisor user memory access + uint64_t sum : 1; + // make executable readable + uint64_t mxr : 1; + // trap virtual memory + uint64_t tvm : 1; + // timeout wait (trap WFI) + uint64_t tw : 1; + // trap SRET + uint64_t tsr : 1; + uint64_t unused2 : 9; + // U-mode XLEN + uint64_t uxl : 2; + // S-mode XLEN + uint64_t sxl : 2; + uint64_t unused3 : 27; + // status dirty + uint64_t sd : 1; + }; + + uint64_t val; + }; + + mstatus_t(void) { + val = 0; + return; + } + + mstatus_t(uint64_t _val) : val(_val) { + return; + } +}; + +/** + * @brief sstatus 寄存器定义 + */ +struct sstatus_t { + union { + struct { + // Reserved Writes Preserve Values, Reads Ignore Values (WPRI) + uint64_t wpri1 : 1; + // interrupt enable + uint64_t sie : 1; + uint64_t wpri12 : 3; + // previous interrupt enable + uint64_t spie : 1; + uint64_t ube : 1; + uint64_t wpri3 : 1; + // previous mode (supervisor) + uint64_t spp : 1; + uint64_t wpri4 : 4; + // FPU status + uint64_t fs : 2; + // extensions status + uint64_t xs : 2; + uint64_t wpri5 : 1; + // permit supervisor user memory access + uint64_t sum : 1; + // make executable readable + uint64_t mxr : 1; + uint64_t wpri6 : 12; + // U-mode XLEN + uint64_t uxl : 2; + uint64_t wpri7 : 29; + // status dirty + uint64_t sd : 1; + }; + + uint64_t val; + }; + + sstatus_t(void) { + val = 0; + return; + } + + sstatus_t(uint64_t _val) : val(_val) { + return; + } + + friend std::ostream& + operator<<(std::ostream& _os, const sstatus_t& _sstatus) { + printf("val: 0x%p, sie: %s, spie: %s, spp: %s", _sstatus.val, + (_sstatus.sie == true ? "enable" : "disable"), + (_sstatus.spie == true ? "enable" : "disable"), + (_sstatus.spp == true ? "S mode" : "U mode")); + return _os; + } +}; /** * @brief 读取 sstatus 寄存器 * @return uint64_t 读取到的值 */ -static inline uint64_t READ_SSTATUS(void) { - uint64_t x; - __asm__ volatile("csrr %0, sstatus" : "=r"(x)); +inline static sstatus_t READ_SSTATUS(void) { + sstatus_t x; + asm("csrr %0, sstatus" : "=r"(x)); return x; } @@ -52,8 +319,8 @@ static inline uint64_t READ_SSTATUS(void) { * @brief 写 sstatus 寄存器 * @param _x 要写的值 */ -static inline void WRITE_SSTATUS(uint64_t _x) { - __asm__ volatile("csrw sstatus, %0" : : "r"(_x)); +inline static void WRITE_SSTATUS(sstatus_t _x) { + asm("csrw sstatus, %0" : : "r"(_x)); } /** @@ -61,9 +328,9 @@ static inline void WRITE_SSTATUS(uint64_t _x) { * @return uint64_t 读取到的值 * @note Supervisor Interrupt Pending */ -static inline uint64_t READ_SIP(void) { +inline static uint64_t READ_SIP(void) { uint64_t x; - __asm__ volatile("csrr %0, sip" : "=r"(x)); + asm("csrr %0, sip" : "=r"(x)); return x; } @@ -71,8 +338,8 @@ static inline uint64_t READ_SIP(void) { * @brief 写 sip * @param _x 要写的值 */ -static inline void WRITE_SIP(uint64_t _x) { - __asm__ volatile("csrw sip, %0" : : "r"(_x)); +inline static void WRITE_SIP(uint64_t _x) { + asm("csrw sip, %0" : : "r"(_x)); return; } @@ -88,9 +355,9 @@ static constexpr const uint64_t SIE_SEIE = 1 << 9; * @brief 读 sie * @return uint64_t 读到的值 */ -static inline uint64_t READ_SIE(void) { +inline static uint64_t READ_SIE(void) { uint64_t x; - __asm__ volatile("csrr %0, sie" : "=r"(x)); + asm("csrr %0, sie" : "=r"(x)); return x; } @@ -98,8 +365,8 @@ static inline uint64_t READ_SIE(void) { * @brief 写 sie * @param _x 要写的值 */ -static inline void WRITE_SIE(uint64_t _x) { - __asm__ volatile("csrw sie, %0" : : "r"(_x)); +inline static void WRITE_SIE(uint64_t _x) { + asm("csrw sie, %0" : : "r"(_x)); return; } @@ -109,9 +376,9 @@ static inline void WRITE_SIE(uint64_t _x) { * @note machine exception program counter, holds the instruction address to * which a return from exception will go. */ -static inline uint64_t READ_SEPC(void) { +inline static uint64_t READ_SEPC(void) { uint64_t x; - __asm__ volatile("csrr %0, sepc" : "=r"(x)); + asm("csrr %0, sepc" : "=r"(x)); return x; } @@ -119,8 +386,8 @@ static inline uint64_t READ_SEPC(void) { * @brief 写 sepc * @param _x 要写的值 */ -static inline void WRITE_SEPC(uint64_t _x) { - __asm__ volatile("csrw sepc, %0" : : "r"(_x)); +inline static void WRITE_SEPC(uint64_t _x) { + asm("csrw sepc, %0" : : "r"(_x)); return; } @@ -129,9 +396,9 @@ static inline void WRITE_SEPC(uint64_t _x) { * @return uint64_t 读到的值 * @note Supervisor Trap-Vector Base Address low two bits are mode. */ -static inline uint64_t READ_STVEC(void) { +inline static uint64_t READ_STVEC(void) { uint64_t x; - __asm__ volatile("csrr %0, stvec" : "=r"(x)); + asm("csrr %0, stvec" : "=r"(x)); return x; } @@ -139,20 +406,20 @@ static inline uint64_t READ_STVEC(void) { * @brief 写 stvec * @param _x 要写的值 */ -static inline void WRITE_STVEC(uint64_t _x) { - __asm__ volatile("csrw stvec, %0" : : "r"(_x)); +inline static void WRITE_STVEC(uint64_t _x) { + asm("csrw stvec, %0" : : "r"(_x)); return; } /// 中断模式 直接 -static constexpr const uint64_t TVEC_DIRECT = 0xFFFFFFFFFFFFFFFC; +static constexpr const uint64_t TVEC_DIRECT = 0xFFFFFFFFFFFFFFFC; /// 中断模式 向量 static constexpr const uint64_t TVEC_VECTORED = 0xFFFFFFFFFFFFFFFD; /** * @brief 设置中断模式,直接 */ -static inline void STVEC_DIRECT(void) { +inline static void STVEC_DIRECT(void) { uint64_t stvec = READ_STVEC(); stvec = stvec & TVEC_DIRECT; WRITE_STVEC(stvec); @@ -162,57 +429,40 @@ static inline void STVEC_DIRECT(void) { /** * @brief 设置中断模式,向量 */ -static inline void STVEC_VECTORED(void) { +inline static void STVEC_VECTORED(void) { uint64_t stvec = READ_STVEC(); stvec = stvec & TVEC_VECTORED; WRITE_STVEC(stvec); return; } -/// sv39 虚拟内存模式 -static constexpr const uint64_t SATP_SV39 = (uint64_t)8 << 60; - /** - * @brief 设置 sv39 虚拟内存模式 - * @param _pgd 要设置的页目录 - * @return constexpr uintptr_t 设置好的页目录 - */ -static constexpr uintptr_t SET_SV39(uintptr_t _pgd) { - return (SATP_SV39 | (_pgd >> 12)); -} - -/** - * @brief 设置页目录 + * @brief 设置页目录,仅更改 ppn * @param _x 要设置的页目录 * @note supervisor address translation and protection; holds the address of * the page table. + * @todo 需要判断 _x 是否已经处理过 */ -static inline void SET_PGD(uintptr_t _x) { - uintptr_t old; +inline static void SET_PGD(uintptr_t _x) { + satp_t satp; // 读取现在的 pgd - __asm__ volatile("csrr %0, satp" : "=r"(old)); - // 如果开启了 sv39 - if ((old & SATP_SV39) == SATP_SV39) { - // 将新的页目录也设为开启 - _x = SET_SV39(_x); - } - __asm__ volatile("csrw satp, %0" : : "r"(_x)); + asm("csrr %0, satp" : "=r"(satp)); + // 更改 ppn + // satp.ppn = _x & satp_t::PPN_MASK; + satp.ppn = _x >> satp_t::PPN_OFFSET; + // 写回 + asm("csrw satp, %0" : : "r"(satp)); return; } /** - * @brief 获取页目录 + * @brief 获取页目录,仅获取 ppn * @return uintptr_t 页目录 */ -static inline uintptr_t GET_PGD(void) { - uintptr_t x; - __asm__ volatile("csrr %0, satp" : "=r"(x)); - // 如果开启了虚拟内存,恢复为原始格式 - if ((x & SATP_SV39) == SATP_SV39) { - x = (x & 0x7FFFFFFFFF); - x = (x << 12); - } - return x; +inline static uintptr_t GET_PGD(void) { + satp_t satp; + asm("csrr %0, satp" : "=r"(satp)); + return satp.ppn << satp_t::PPN_OFFSET; } /** @@ -220,25 +470,48 @@ static inline uintptr_t GET_PGD(void) { * @return true 成功 * @return false 失败 */ -static inline bool ENABLE_PG(void) { +inline static bool ENABLE_PG(void) { uintptr_t x = GET_PGD(); - SET_PGD(SET_SV39(x)); + satp_t satp; + satp.ppn = x >> satp_t::PPN_OFFSET; + satp.asid = 0; + satp.mode = satp_t::SV39; + asm("csrw satp, %0" : : "r"(satp)); info("paging enabled.\n"); return true; } -/// [31]=1 interrupt, else exception -static constexpr const uint64_t CAUSE_INTR_MASK = 0x8000000000000000; +/** + * @brief 读 sscratch 寄存器 + * @param _x 要写的值 + */ +inline static uint64_t READ_SSCRATCH(void) { + uint64_t x; + __asm__ volatile("csrr %0, sscratch" : "=r"(x)); + return x; +} + +/** + * @brief 写 sscratch 寄存器 + * @param _x 要写的值 + */ +inline static void WRITE_SSCRATCH(uint64_t _x) { + asm("csrw sscratch, %0" : : "r"(_x)); + return; +} + +/// [63]==1 interrupt, else exception +static constexpr const uint64_t CAUSE_INTR_MASK = 1ULL << 63; /// low bits show code -static constexpr const uint64_t CAUSE_CODE_MASK = 0x7FFFFFFFFFFFFFFF; +static constexpr const uint64_t CAUSE_CODE_MASK = ~CAUSE_INTR_MASK; /** * @brief 读 scause 寄存器 Supervisor Trap Cause * @return uint64_t 读到的值 */ -static inline uint64_t READ_SCAUSE(void) { +inline static uint64_t READ_SCAUSE(void) { uint64_t x; - __asm__ volatile("csrr %0, scause" : "=r"(x)); + asm("csrr %0, scause" : "=r"(x)); return x; } @@ -246,9 +519,9 @@ static inline uint64_t READ_SCAUSE(void) { * @brief 读 stval 寄存器 Supervisor Trap Value * @return uint64_t 读到的值 */ -static inline uint64_t READ_STVAL(void) { +inline static uint64_t READ_STVAL(void) { uint64_t x; - __asm__ volatile("csrr %0, stval" : "=r"(x)); + asm("csrr %0, stval" : "=r"(x)); return x; } @@ -256,27 +529,45 @@ static inline uint64_t READ_STVAL(void) { * @brief 读 time 寄存器 supervisor-mode cycle counter * @return uint64_t 读到的值 */ -static inline uint64_t READ_TIME(void) { +inline static uint64_t READ_TIME(void) { uint64_t x; - // __asm__ volatile("csrr %0, time" : "=r" (x) ); + // asm ("csrr %0, time" : "=r" (x) ); // this instruction will trap in SBI - __asm__ volatile("rdtime %0" : "=r"(x)); + asm("rdtime %0" : "=r"(x)); return x; } /** * @brief 允许中断 */ -static inline void ENABLE_INTR(void) { - WRITE_SSTATUS(READ_SSTATUS() | SSTATUS_SIE); +inline static void ENABLE_INTR(void) { + WRITE_SSTATUS(READ_SSTATUS().val | SSTATUS_SIE); + return; +} + +/** + * @brief 允许中断 + * @param _sstatus 要设置的 sstatus + */ +inline static void ENABLE_INTR(sstatus_t& _sstatus) { + _sstatus.sie = true; + return; +} + +/** + * @brief 禁止中断 + */ +inline static void DISABLE_INTR(void) { + WRITE_SSTATUS(READ_SSTATUS().val & ~SSTATUS_SIE); return; } /** * @brief 禁止中断 + * @param _sstatus 要设置的原 sstatus 值 */ -static inline void DISABLE_INTR(void) { - WRITE_SSTATUS(READ_SSTATUS() & ~SSTATUS_SIE); +inline static void DISABLE_INTR(sstatus_t& _sstatus) { + _sstatus.sie = false; return; } @@ -285,18 +576,18 @@ static inline void DISABLE_INTR(void) { * @return true 允许 * @return false 禁止 */ -static inline bool STATUS_INTR(void) { - uint64_t x = READ_SSTATUS(); - return (x & SSTATUS_SIE) != 0; +inline static bool STATUS_INTR(void) { + sstatus_t x = READ_SSTATUS(); + return x.sie; } /** * @brief 读 sp 寄存器 * @return uint64_t 读到的值 */ -static inline uint64_t READ_SP(void) { +inline static uint64_t READ_SP(void) { uint64_t x; - __asm__ volatile("mv %0, sp" : "=r"(x)); + asm("mv %0, sp" : "=r"(x)); return x; } @@ -304,9 +595,9 @@ static inline uint64_t READ_SP(void) { * @brief 读 tp 寄存器 * @return uint64_t 读到的值 */ -static inline uint64_t READ_TP(void) { +inline static uint64_t READ_TP(void) { uint64_t x; - __asm__ volatile("mv %0, tp" : "=r"(x)); + asm("mv %0, tp" : "=r"(x)); return x; } @@ -314,8 +605,8 @@ static inline uint64_t READ_TP(void) { * @brief 写 tp 寄存器 * @param _x 要写的值 */ -static inline void WRITE_TP(uint64_t _x) { - __asm__ volatile("mv tp, %0" : : "r"(_x)); +inline static void WRITE_TP(uint64_t _x) { + asm("mv tp, %0" : : "r"(_x)); return; } @@ -323,21 +614,195 @@ static inline void WRITE_TP(uint64_t _x) { * @brief 读 ra 寄存器 * @return uint64_t 读到的值 */ -static inline uint64_t READ_RA(void) { +inline static uint64_t READ_RA(void) { uint64_t x; - __asm__ volatile("mv %0, ra" : "=r"(x)); + asm("mv %0, ra" : "=r"(x)); return x; } /** * @brief 刷新 tlb */ -static inline void VMM_FLUSH(uintptr_t) { +inline static void VMM_FLUSH(uintptr_t) { // the zero, zero means flush all TLB entries. - __asm__ volatile("sfence.vma zero, zero"); + asm("sfence.vma zero, zero"); return; } -}; // namespace CPU +/** + * @brief 通用寄存器 + */ +struct xregs_t { + uintptr_t zero; + uintptr_t ra; + uintptr_t sp; + uintptr_t gp; + uintptr_t tp; + uintptr_t t0; + uintptr_t t1; + uintptr_t t2; + uintptr_t s0; + uintptr_t s1; + uintptr_t a0; + uintptr_t a1; + uintptr_t a2; + uintptr_t a3; + uintptr_t a4; + uintptr_t a5; + uintptr_t a6; + uintptr_t a7; + uintptr_t s2; + uintptr_t s3; + uintptr_t s4; + uintptr_t s5; + uintptr_t s6; + uintptr_t s7; + uintptr_t s8; + uintptr_t s9; + uintptr_t s10; + uintptr_t s11; + uintptr_t t3; + uintptr_t t4; + uintptr_t t5; + uintptr_t t6; + + friend std::ostream& operator<<(std::ostream& _os, const xregs_t& _xregs) { + printf("zero: 0x%p, ", _xregs.zero); + printf("ra: 0x%p, ", _xregs.ra); + printf("sp: 0x%p, ", _xregs.sp); + printf("gp: 0x%p\n", _xregs.gp); + printf("tp: 0x%p, ", _xregs.tp); + printf("t0: 0x%p, ", _xregs.t0); + printf("t1: 0x%p, ", _xregs.t1); + printf("t2: 0x%p\n", _xregs.t2); + printf("s0: 0x%p, ", _xregs.s0); + printf("s1: 0x%p, ", _xregs.s1); + printf("a0: 0x%p, ", _xregs.a0); + printf("a1: 0x%p\n", _xregs.a1); + printf("a2: 0x%p, ", _xregs.a2); + printf("a3: 0x%p, ", _xregs.a3); + printf("a4: 0x%p, ", _xregs.a4); + printf("a5: 0x%p\n", _xregs.a5); + printf("a6: 0x%p, ", _xregs.a6); + printf("a7: 0x%p, ", _xregs.a7); + printf("s2: 0x%p, ", _xregs.s2); + printf("s3: 0x%p\n", _xregs.s3); + printf("s4: 0x%p, ", _xregs.s4); + printf("s5: 0x%p, ", _xregs.s5); + printf("s6: 0x%p, ", _xregs.s6); + printf("s7: 0x%p\n", _xregs.s7); + printf("s8: 0x%p, ", _xregs.s8); + printf("s9: 0x%p, ", _xregs.s9); + printf("s10: 0x%p, ", _xregs.s10); + printf("s11: 0x%p\n", _xregs.s11); + printf("t3: 0x%p, ", _xregs.t3); + printf("t4: 0x%p, ", _xregs.t4); + printf("t5: 0x%p, ", _xregs.t5); + printf("t6: 0x%p", _xregs.t6); + return _os; + } +}; + +/** + * @brief 浮点寄存器 + */ +struct fregs_t { + uintptr_t ft0; + uintptr_t ft1; + uintptr_t ft2; + uintptr_t ft3; + uintptr_t ft4; + uintptr_t ft5; + uintptr_t ft6; + uintptr_t ft7; + uintptr_t fs0; + uintptr_t fs1; + uintptr_t fa0; + uintptr_t fa1; + uintptr_t fa2; + uintptr_t fa3; + uintptr_t fa4; + uintptr_t fa5; + uintptr_t fa6; + uintptr_t fa7; + uintptr_t fs2; + uintptr_t fs3; + uintptr_t fs4; + uintptr_t fs5; + uintptr_t fs6; + uintptr_t fs7; + uintptr_t fs8; + uintptr_t fs9; + uintptr_t fs10; + uintptr_t fs11; + uintptr_t ft8; + uintptr_t ft9; + uintptr_t ft10; + uintptr_t ft11; + + friend std::ostream& operator<<(std::ostream& _os, const fregs_t& _fregs) { + printf("ft0: 0x%p, ", _fregs.ft0); + printf("ft1: 0x%p, ", _fregs.ft1); + printf("ft2: 0x%p, ", _fregs.ft2); + printf("ft3: 0x%p\n", _fregs.ft3); + printf("ft4: 0x%p, ", _fregs.ft4); + printf("ft5: 0x%p, ", _fregs.ft5); + printf("ft6: 0x%p, ", _fregs.ft6); + printf("ft7: 0x%p\n", _fregs.ft7); + printf("fs0: 0x%p, ", _fregs.fs0); + printf("fs1: 0x%p, ", _fregs.fs1); + printf("fa0: 0x%p, ", _fregs.fa0); + printf("fa1: 0x%p\n", _fregs.fa1); + printf("fa2: 0x%p, ", _fregs.fa2); + printf("fa3: 0x%p, ", _fregs.fa3); + printf("fa4: 0x%p, ", _fregs.fa4); + printf("fa5: 0x%p\n", _fregs.fa5); + printf("fa6: 0x%p, ", _fregs.fa6); + printf("fa7: 0x%p, ", _fregs.fa7); + printf("fs2: 0x%p, ", _fregs.fs2); + printf("fs3: 0x%p\n", _fregs.fs3); + printf("fs4: 0x%p, ", _fregs.fs4); + printf("fs5: 0x%p, ", _fregs.fs5); + printf("fs6: 0x%p, ", _fregs.fs6); + printf("fs7: 0x%p\n", _fregs.fs7); + printf("fs8: 0x%p, ", _fregs.fs8); + printf("fs9: 0x%p, ", _fregs.fs9); + printf("fs10: 0x%p, ", _fregs.fs10); + printf("fs11: 0x%p\n", _fregs.fs11); + printf("ft8: 0x%p, ", _fregs.ft8); + printf("ft9: 0x%p, ", _fregs.ft9); + printf("ft10: 0x%p, ", _fregs.ft10); + printf("ft11: 0x%p", _fregs.ft11); + return _os; + } +}; + +/** + * @brief 所有寄存器,在中断时使用,共 32+32+7=71 个 + */ +struct all_regs_t { + xregs_t xregs; + fregs_t fregs; + uintptr_t sepc; + uintptr_t stval; + uintptr_t scause; + uintptr_t sie; + sstatus_t sstatus; + satp_t satp; + uintptr_t sscratch; + + friend std::ostream& + operator<<(std::ostream& _os, const all_regs_t& _all_regs) { + (void)_all_regs.fregs; + _os << _all_regs.xregs << std::endl; + printf("sepc: 0x%p, stval: 0x%p, scause: 0x%p, sie: 0x%p, sstatus: " + "0x%p, satp: 0x%p, sscratch: 0x%p", + _all_regs.sepc, _all_regs.stval, _all_regs.scause, _all_regs.sie, + _all_regs.sstatus.val, _all_regs.satp.val, _all_regs.sscratch); + return _os; + } +}; + +}; // namespace CPU -#endif /* _CPU_HPP_ */ +#endif /* SIMPLEKERNEL_CPU_HPP */ diff --git a/src/arch/riscv64/intr/clint.cpp b/src/arch/riscv64/intr/clint.cpp index 33e877537..d9f0edd5f 100644 --- a/src/arch/riscv64/intr/clint.cpp +++ b/src/arch/riscv64/intr/clint.cpp @@ -15,15 +15,14 @@ * */ -#include "cpu.hpp" -#include "stdio.h" -#include "vmm.h" #include "boot_info.h" -#include "resource.h" -#include "intr.h" #include "cpu.hpp" +#include "cstdio" +#include "intr.h" +#include "resource.h" +#include "vmm.h" -CLINT &CLINT::get_instance(void) { +CLINT& CLINT::get_instance(void) { /// 定义全局 CLINT 对象 static CLINT clint; return clint; @@ -32,8 +31,8 @@ CLINT &CLINT::get_instance(void) { int32_t CLINT::init(void) { // 映射 clint 地址 resource_t resource = BOOT_INFO::get_clint(); - for (uintptr_t a = resource.mem.addr; - a < resource.mem.addr + resource.mem.len; a += 0x1000) { + for (uintptr_t a = resource.mem.addr; + a < resource.mem.addr + resource.mem.len; a += COMMON::PAGE_SIZE) { VMM::get_instance().mmap(VMM::get_instance().get_pgd(), a, a, VMM_PAGE_READABLE | VMM_PAGE_WRITABLE); } diff --git a/src/arch/riscv64/intr/include/intr.h b/src/arch/riscv64/intr/include/intr.h index 1c6ce77f2..ed102cdc1 100644 --- a/src/arch/riscv64/intr/include/intr.h +++ b/src/arch/riscv64/intr/include/intr.h @@ -14,54 +14,62 @@ * */ -#ifndef _INTR_H_ -#define _INTR_H_ +#ifndef SIMPLEKERNEL_INTR_H +#define SIMPLEKERNEL_INTR_H -#include "stdint.h" +#include "cpu.hpp" +#include "cstdint" void handler_default(void); class INTR { public: - /// 中断处理函数指针 - typedef void (*interrupt_handler_t)(void); + /** + * @brief 中断处理函数指针 + * @param _argc 参数个数 + * @param _argv 参数列表 + * @return int32_t 返回值,0 成功 + */ + typedef int32_t (*interrupt_handler_t)(int _argc, char** _argv); private: /// 异常名 - static constexpr const char *const excp_names[] = { - "Instruction Address Misaligned", - "Instruction Access Fault", - "Illegal Instruction", - "Breakpoint", - "Load Address Misaligned", - "Load Access Fault", - "Store/AMO Address Misaligned", - "Store/AMO Access Fault", - "Environment Call from U-mode", - "Environment Call from S-mode", + static constexpr const char* const excp_names[] = { + [CPU::EXCP_INSTRUCTION_ADDRESS_MISALIGNED] + = "Instruction Address Misaligned", + [CPU::EXCP_INSTRUCTION_ACCESS_FAULT] = "Instruction Access Fault", + [CPU::EXCP_ILLEGAL_INSTRUCTION] = "Illegal Instruction", + [CPU::EXCP_BREAKPOINT] = "Breakpoint", + [CPU::EXCP_LOAD_ADDRESS_MISALIGNED] = "Load Address Misaligned", + [CPU::EXCP_LOAD_ACCESS_FAULT] = "Load Access Fault", + [CPU::EXCP_STORE_AMO_ADDRESS_MISALIGNED] + = "Store/AMO Address Misaligned", + [CPU::EXCP_STORE_AMO_ACCESS_FAULT] = "Store/AMO Access Fault", + [CPU::EXCP_ECALL_U] = "Environment Call from U-mode", + [CPU::EXCP_ECALL_S] = "Environment Call from S-mode", "Reserved", - "Environment Call from M-mode", - "Instruction Page Fault", - "Load Page Fault", + [CPU::EXCP_ECALL_M] = "Environment Call from M-mode", + [CPU::EXCP_INSTRUCTION_PAGE_FAULT] = "Instruction Page Fault", + [CPU::EXCP_LOAD_PAGE_FAULT] = "Load Page Fault", "Reserved", - "Store/AMO Page Fault", + [CPU::EXCP_STORE_AMO_PAGE_FAULT] = "Store/AMO Page Fault", "Reserved", }; /// 中断名 - static constexpr const char *const intr_names[] = { - "User Software Interrupt", - "Supervisor Software Interrupt", + static constexpr const char* const intr_names[] = { + [CPU::INTR_SOFT_U] = "User Software Interrupt", + [CPU::INTR_SOFT_S] = "Supervisor Software Interrupt", "Reserved", - "Machine Software Interrupt", - "User Timer Interrupt", - "Supervisor Timer Interrupt", + [CPU::INTR_SOFT_M] = "Machine Software Interrupt", + [CPU::INTR_TIMER_U] = "User Timer Interrupt", + [CPU::INTR_TIMER_S] = "Supervisor Timer Interrupt", "Reserved", - "Machine Timer Interrupt", - "User External Interrupt", - "Supervisor External Interrupt", + [CPU::INTR_TIMER_M] = "Machine Timer Interrupt", + [CPU::INTR_EXTERN_U] = "User External Interrupt", + [CPU::INTR_EXTERN_S] = "Supervisor External Interrupt", "Reserved", - "Machine External Interrupt", + [CPU::INTR_EXTERN_M] = "Machine External Interrupt", "Reserved", "Reserved", "Reserved", @@ -72,35 +80,26 @@ class INTR { /// 最大中断数 static constexpr const uint32_t INTERRUPT_MAX = 16; /// 最大异常数 - static constexpr const uint32_t EXCP_MAX = 16; + static constexpr const uint32_t EXCP_MAX = 16; /// 中断处理函数数组 - interrupt_handler_t interrupt_handlers[INTERRUPT_MAX] - __attribute__((aligned(4))); + interrupt_handler_t interrupt_handlers[INTERRUPT_MAX] + __attribute__((aligned(4))); /// 异常处理函数数组 interrupt_handler_t excp_handlers[EXCP_MAX] __attribute__((aligned(4))); public: - /// 页读错误 - static constexpr const uint8_t EXCP_LOAD_PAGE_FAULT = 13; - /// 页写错误 - static constexpr const uint8_t EXCP_STORE_PAGE_FAULT = 15; - /// S 态时钟中断 - static constexpr const uint8_t INTR_S_TIMER = 5; - /// S 态外部中断 - static constexpr const uint8_t INTR_S_EXTERNEL = 9; - /** * @brief 获取单例 * @return INTR& 静态对象 */ - static INTR &get_instance(void); + static INTR& get_instance(void); /** * @brief 中断初始化 * @return int32_t 成功返回 0 */ - int32_t init(void); + int32_t init(void); /** * @brief 注册中断处理函数 @@ -108,42 +107,48 @@ class INTR { * @param _interrupt_handler 中断处理函数 */ void - register_interrupt_handler(uint8_t _no, - INTR::interrupt_handler_t _interrupt_handler); + register_interrupt_handler(uint8_t _no, + INTR::interrupt_handler_t _interrupt_handler); /** * @brief 注册异常处理函数 * @param _no 异常号 * @param _interrupt_handler 异常处理函数 */ - void register_excp_handler(uint8_t _no, - INTR::interrupt_handler_t _interrupt_handler); + void register_excp_handler(uint8_t _no, + INTR::interrupt_handler_t _interrupt_handler); /** * @brief 执行中断处理 * @param _no 中断号 + * @param _argc 参数个数 + * @param _argv 参数列表 + * @return int32_t 返回值,0 成功 */ - void do_interrupt(uint8_t _no); + int32_t do_interrupt(uint8_t _no, int32_t _argc, char** _argv); /** * @brief 执行异常处理 * @param _no 异常号 + * @param _argc 参数个数 + * @param _argv 参数列表 + * @return int32_t 返回值,0 成功 */ - void do_excp(uint8_t _no); + int32_t do_excp(uint8_t _no, int32_t _argc, char** _argv); /** * @brief 获取中断名 * @param _no 中断号 * @return const char* 中断名 */ - const char *get_intr_name(uint8_t _no) const; + const char* get_intr_name(uint8_t _no) const; /** * @brief 获取异常名 * @param _no 异常号 * @return const char* 异常名 */ - const char *get_excp_name(uint8_t _no) const; + const char* get_excp_name(uint8_t _no) const; }; /** @@ -157,13 +162,13 @@ class CLINT { * @brief 获取单例 * @return CLINT& 静态对象 */ - static CLINT &get_instance(void); + static CLINT& get_instance(void); /** * @brief 初始化 * @return int32_t 成功返回 0 */ - int32_t init(void); + int32_t init(void); }; /** @@ -174,44 +179,49 @@ class CLINT { class PLIC { private: /// 基地址,由 dtb 传递 - uintptr_t base_addr; + static uintptr_t base_addr; /// @todo ? - uint64_t PLIC_PRIORITY; + static uint64_t PLIC_PRIORITY; /// @todo ? - uint64_t PLIC_PENDING; + static uint64_t PLIC_PENDING; /// @todo ? - uint64_t PLIC_SENABLE(uint64_t hart); + inline static uint64_t PLIC_SENABLE(uint64_t _hart); + + inline static uint64_t PLIC_MENABLE(uint64_t _hart); /// @todo ? - uint64_t PLIC_SPRIORITY(uint64_t hart); + inline static uint64_t PLIC_SPRIORITY(uint64_t _hart); + inline static uint64_t PLIC_MPRIORITY(uint64_t _hart); /// @todo ? - uint64_t PLIC_SCLAIM(uint64_t hart); + inline static uint64_t PLIC_SCLAIM(uint64_t _hart); + inline static uint64_t PLIC_MCLAIM(uint64_t _hart); protected: + public: /** * @brief 获取单例 * @return PLIC& 静态对象 */ - static PLIC &get_instance(void); + static PLIC& get_instance(void); /** * @brief 初始化 * @return int32_t 成功返回 0 */ - int32_t init(void); + int32_t init(void); /** * @brief 向 PLIC 询问中断 * 返回发生的外部中断号 * @return uint8_t 中断号 */ - uint8_t get(void); + uint8_t get(void); /** * @brief 告知 PLIC 已经处理了当前 IRQ * @param _no 中断号 */ - void done(uint8_t _no); + void done(uint8_t _no); /** * @brief 设置中断状态 @@ -219,7 +229,7 @@ class PLIC { * @param _status 状态 * @todo 不确定 */ - void set(uint8_t _no, bool _status); + void set(uint8_t _no, bool _status); }; /** @@ -231,12 +241,23 @@ class TIMER { * @brief 获取单例 * @return TIMER& 静态对象 */ - static TIMER &get_instance(void); + static TIMER& get_instance(void); /** * @brief 初始化 */ - void init(void); + void init(void); }; -#endif /* _INTR_H_ */ +/** + * @brief 缺页读处理 + */ +int32_t pg_load_excp(int, char**); + +/** + * @brief 缺页写处理 + * @todo 需要读权限吗?测试发现没有读权限不行,原因未知 + */ +int32_t pg_store_excp(int, char**); + +#endif /* SIMPLEKERNEL_INTR_H */ diff --git a/src/arch/riscv64/intr/intr.cpp b/src/arch/riscv64/intr/intr.cpp index d1e613de1..12b9497da 100644 --- a/src/arch/riscv64/intr/intr.cpp +++ b/src/arch/riscv64/intr/intr.cpp @@ -1,7 +1,7 @@ /** * @file intr.cpp - * @brief 中断抽象 + * @brief 中断实现 * @author Zone.N (Zone.Niuzh@hotmail.com) * @version 1.0 * @date 2021-09-18 @@ -14,39 +14,56 @@ * */ -#include "cpu.hpp" -#include "stdio.h" #include "intr.h" #include "cpu.hpp" -#include "vmm.h" +#include "cstdio" /** * @brief 中断处理函数 * @param _scause 原因 * @param _sepc 值 * @param _stval 值 + * @param _scause 值 + * @param _all_regs 保存在栈上的所有寄存器,实际上是 sp + * @param _sie 值 + * @param _sstatus 值 + * @param _sscratch 值 */ -extern "C" void trap_handler(uint64_t _scause, uint64_t _sepc, - uint64_t _stval) { - +extern "C" void +trap_handler(uintptr_t _sepc, uintptr_t _stval, uintptr_t _scause, + CPU::all_regs_t* _all_regs, uintptr_t _sie, + CPU::sstatus_t _sstatus, CPU::satp_t _satp, uintptr_t _sscratch) { // 消除 unused 警告 (void)_sepc; (void)_stval; + (void)_scause; + (void)_all_regs; + (void)_sie; + (void)_sstatus; + (void)_satp; + (void)_sscratch; #define DEBUG #ifdef DEBUG - info("scause: 0x%p, sepc: 0x%p, stval: 0x%p.\n", _scause, _sepc, _stval); -#undef DEBUG + info("sepc: 0x%p, stval: 0x%p, scause: 0x%p, all_regs(sp): 0x%p, sie: " + "0x%p\nsstatus: ", + _sepc, _stval, _scause, _all_regs, _sie); + std::cout << _sstatus << ", \nsatp: " << _satp << ", \n"; + info("sscratch: 0x%p\n", _sscratch); +// std::cout << *_all_regs << std::endl; +# undef DEBUG #endif if (_scause & CPU::CAUSE_INTR_MASK) { // 中断 // #define DEBUG #ifdef DEBUG - info("intr: %s.\n", INTR::get_instance().get_intr_name( - _scause & CPU::CAUSE_CODE_MASK)); -#undef DEBUG + info("intr: %s.\n", + INTR::get_instance().get_intr_name(_scause + & CPU::CAUSE_CODE_MASK)); +# undef DEBUG #endif // 跳转到对应的处理函数 - INTR::get_instance().do_interrupt(_scause & CPU::CAUSE_CODE_MASK); + INTR::get_instance().do_interrupt(_scause & CPU::CAUSE_CODE_MASK, 0, + nullptr); } else { // 异常 @@ -54,10 +71,12 @@ extern "C" void trap_handler(uint64_t _scause, uint64_t _sepc, // #define DEBUG #ifdef DEBUG warn("excp: %s.\n", - INTR::get_instance().excp_name(_scause & CPU::CAUSE_CODE_MASK)); -#undef DEBUG + INTR::get_instance().get_excp_name(_scause + & CPU::CAUSE_CODE_MASK)); +# undef DEBUG #endif - INTR::get_instance().do_excp(_scause & CPU::CAUSE_CODE_MASK); + INTR::get_instance().do_excp(_scause & CPU::CAUSE_CODE_MASK, 0, + nullptr); } return; } @@ -65,41 +84,17 @@ extern "C" void trap_handler(uint64_t _scause, uint64_t _sepc, /// 中断处理入口 intr_s.S extern "C" void trap_entry(void); -/** - * @brief 缺页处理 - */ -void pg_load_excp(void) { - uintptr_t addr = CPU::READ_STVAL(); - // 映射页 - VMM::get_instance().mmap(VMM::get_instance().get_pgd(), addr, addr, - VMM_PAGE_READABLE); - info("pg_load_excp done: 0x%p.\n", addr); - return; -} - -/** - * @brief 缺页处理 - */ -void pg_store_excp(void) { - uintptr_t addr = CPU::READ_STVAL(); - // 映射页 - VMM::get_instance().mmap(VMM::get_instance().get_pgd(), addr, addr, - VMM_PAGE_WRITABLE | VMM_PAGE_READABLE); - info("pg_store_excp done: 0x%p.\n", addr); - return; -} - /** * @brief 默认使用的中断处理函数 */ -void handler_default(void) { +int32_t handler_default(int, char**) { while (1) { ; } - return; + return 0; } -INTR &INTR::get_instance(void) { +INTR& INTR::get_instance(void) { /// 定义全局 INTR 对象 static INTR intr; return intr; @@ -110,27 +105,27 @@ int32_t INTR::init(void) { CPU::WRITE_STVEC((uintptr_t)trap_entry); // 直接跳转到处理函数 CPU::STVEC_DIRECT(); - // 内部中断初始化 - CLINT::get_instance().init(); - // 外部中断初始化 - PLIC::get_instance().init(); // 设置处理函数 - for (auto &i : interrupt_handlers) { + for (auto& i : interrupt_handlers) { i = handler_default; } - for (auto &i : excp_handlers) { + for (auto& i : excp_handlers) { i = handler_default; } + // 内部中断初始化 + CLINT::get_instance().init(); + // 外部中断初始化 + PLIC::get_instance().init(); // 注册缺页中断 - register_excp_handler(EXCP_LOAD_PAGE_FAULT, pg_load_excp); + register_excp_handler(CPU::EXCP_LOAD_PAGE_FAULT, pg_load_excp); // 注册缺页中断 - register_excp_handler(EXCP_STORE_PAGE_FAULT, pg_store_excp); + register_excp_handler(CPU::EXCP_STORE_AMO_PAGE_FAULT, pg_store_excp); info("intr init.\n"); return 0; } void INTR::register_interrupt_handler( - uint8_t _no, INTR::interrupt_handler_t _interrupt_handler) { + uint8_t _no, INTR::interrupt_handler_t _interrupt_handler) { interrupt_handlers[_no] = _interrupt_handler; return; } @@ -141,20 +136,18 @@ void INTR::register_excp_handler(uint8_t _no, return; } -void INTR::do_interrupt(uint8_t _no) { - interrupt_handlers[_no](); - return; +int32_t INTR::do_interrupt(uint8_t _no, int32_t _argc, char** _argv) { + return interrupt_handlers[_no](_argc, _argv); } -void INTR::do_excp(uint8_t _no) { - excp_handlers[_no](); - return; +int32_t INTR::do_excp(uint8_t _no, int32_t _argc, char** _argv) { + return excp_handlers[_no](_argc, _argv); } -const char *INTR::get_intr_name(uint8_t _no) const { +const char* INTR::get_intr_name(uint8_t _no) const { return intr_names[_no]; } -const char *INTR::get_excp_name(uint8_t _no) const { +const char* INTR::get_excp_name(uint8_t _no) const { return excp_names[_no]; } diff --git a/src/arch/riscv64/intr/intr_s.S b/src/arch/riscv64/intr/intr_s.S index a122c998f..5b26ad1a1 100644 --- a/src/arch/riscv64/intr/intr_s.S +++ b/src/arch/riscv64/intr/intr_s.S @@ -14,80 +14,37 @@ * */ -.equ REGBYTES, 8 -.equ SAVE_REGS, 16 -.equ CONTEXT_SIZE, (SAVE_REGS * REGBYTES) +#include "context.S" -.macro lx a, b -ld \a, \b -.endm - -.macro sx a, b -sd \a, \b -.endm - -.macro lxsp a, b -ld \a, ((\b)*REGBYTES)(sp) -.endm - -.macro sxsp a, b -sd \a, ((\b)*REGBYTES)(sp) -.endm +// clang-format off .section .text - -// push all registers, call trap_handler(), restore, return. -.extern irq_handler +// 保存所有寄存器 .globl trap_entry .extern trap_handler .align 4 trap_entry: - // make room to save registers. - addi sp, sp, -CONTEXT_SIZE - - sxsp ra, 0 - sxsp a0, 1 - sxsp a1, 2 - sxsp a2, 3 - sxsp a3, 4 - sxsp a4, 5 - sxsp a5, 6 - sxsp a6, 7 - sxsp a7, 8 - sxsp t0, 9 - sxsp t1, 10 - sxsp t2, 11 - sxsp t3, 12 - sxsp t4, 13 - sxsp t5, 14 - sxsp t6, 15 - - // Invoke the handler. - // intr.cpp - csrr a0, scause - csrr a1, sepc - csrr a2, stval + // 将所有寄存器保存到栈上 + // 在栈上留出保存寄存器的空间 + addi sp, sp, -ALL_SIZE + all_regs_save sp + + // 调用 intr.cpp: trap_handler + // 传递参数 + csrr a0, sepc + csrr a1, stval + csrr a2, scause + mv a3, sp + csrr a4, sie + csrr a5, sstatus + csrr a6, satp + csrr a7, sscratch jal trap_handler - // Restore registers. - lxsp ra, 0 - lxsp a0, 1 - lxsp a1, 2 - lxsp a2, 3 - lxsp a3, 4 - lxsp a4, 5 - lxsp a5, 6 - lxsp a6, 7 - lxsp a7, 8 - lxsp t0, 9 - lxsp t1, 10 - lxsp t2, 11 - lxsp t3, 12 - lxsp t4, 13 - lxsp t5, 14 - lxsp t6, 15 - - addi sp, sp, CONTEXT_SIZE + // 从栈上恢复所有寄存器 + all_regs_load sp + // 释放栈上用于保存寄存器的空间 + addi sp, sp, ALL_SIZE - // return to whatever we were doing in the kernel. + // 跳转到 sepc 处执行 sret diff --git a/src/arch/riscv64/intr/page_fault.cpp b/src/arch/riscv64/intr/page_fault.cpp new file mode 100644 index 000000000..1d452d208 --- /dev/null +++ b/src/arch/riscv64/intr/page_fault.cpp @@ -0,0 +1,63 @@ + +/** + * @file page_fault.cpp + * @brief 页错误处理 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2022-03-27 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2022-03-27Zone.Niuzh新建文件 + *
+ */ + +#include "cpu.hpp" +#include "cstdint" +#include "cstdio" +#include "pmm.h" +#include "vmm.h" + +int32_t pg_load_excp(int, char**) { + uintptr_t addr = CPU::READ_STVAL(); + uintptr_t pa = 0x0; + auto is_mmap + = VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), addr, &pa); + // 如果 is_mmap 为 true,说明已经应映射过了 + if (is_mmap == true) { + // 直接映射 + VMM::get_instance().mmap(VMM::get_instance().get_pgd(), addr, pa, + VMM_PAGE_READABLE); + } + else { + // 分配一页物理内存进行映射 + pa = PMM::get_instance().alloc_page_kernel(); + VMM::get_instance().mmap(VMM::get_instance().get_pgd(), addr, pa, + VMM_PAGE_READABLE); + } + info("pg_load_excp done: 0x%p.\n", addr); + return 0; +} + +int32_t pg_store_excp(int, char**) { + uintptr_t addr = CPU::READ_STVAL(); + uintptr_t pa = 0x0; + auto is_mmap + = VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), addr, &pa); + // 如果 is_mmap 为 true,说明已经应映射过了 + if (is_mmap == true) { + // 直接映射 + VMM::get_instance().mmap(VMM::get_instance().get_pgd(), addr, pa, + VMM_PAGE_READABLE | VMM_PAGE_WRITABLE); + } + else { + // 分配一页物理内存进行映射 + pa = PMM::get_instance().alloc_page_kernel(); + VMM::get_instance().mmap(VMM::get_instance().get_pgd(), addr, pa, + VMM_PAGE_READABLE | VMM_PAGE_WRITABLE); + } + info("pg_store_excp done: 0x%p.\n", addr); + return 0; +} diff --git a/src/arch/riscv64/intr/plic.cpp b/src/arch/riscv64/intr/plic.cpp index 048840583..3b58c3b6d 100755 --- a/src/arch/riscv64/intr/plic.cpp +++ b/src/arch/riscv64/intr/plic.cpp @@ -14,42 +14,54 @@ * */ -#include "stdint.h" -#include "stdio.h" -#include "cpu.hpp" -#include "pmm.h" -#include "vmm.h" #include "boot_info.h" -#include "io.h" +#include "cpu.hpp" +#include "cstdint" +#include "cstdio" #include "intr.h" +#include "io.h" +#include "vmm.h" -/// 这个值在启动时由 opensbi 传递,暂时写死 -static constexpr const uint64_t hart = 0; +uint64_t PLIC::base_addr; +uint64_t PLIC::PLIC_PRIORITY; +uint64_t PLIC::PLIC_PENDING; /** * @brief 外部中断处理 */ -static void externel_intr(void) { +static int32_t external_intr(int, char**) { // 读取中断号 auto no = PLIC::get_instance().get(); // 根据中断号判断设备 - printf("externel_intr: 0x%X.\n", no); - return; + printf("external_intr: 0x%X.\n", no); + return 0; } uint64_t PLIC::PLIC_SENABLE(uint64_t _hart) { return base_addr + 0x2080 + _hart * 0x100; } +uint64_t PLIC::PLIC_MENABLE(uint64_t _hart) { + return base_addr + 0x2000 + _hart * 0x100; +} + uint64_t PLIC::PLIC_SPRIORITY(uint64_t _hart) { return base_addr + 0x201000 + _hart * 0x2000; } +uint64_t PLIC::PLIC_MPRIORITY(uint64_t _hart) { + return base_addr + 0x200000 + _hart * 0x2000; +} + uint64_t PLIC::PLIC_SCLAIM(uint64_t _hart) { return base_addr + 0x201004 + _hart * 0x2000; } -PLIC &PLIC::get_instance(void) { +uint64_t PLIC::PLIC_MCLAIM(uint64_t _hart) { + return base_addr + 0x200004 + _hart * 0x2000; +} + +PLIC& PLIC::get_instance(void) { /// 定义全局 PLIC 对象 static PLIC plic; return plic; @@ -61,17 +73,18 @@ int32_t PLIC::init(void) { base_addr = resource.mem.addr; PLIC_PRIORITY = base_addr + 0x0; PLIC_PENDING = base_addr + 0x1000; - for (uintptr_t a = resource.mem.addr; - a < resource.mem.addr + resource.mem.len; a += 0x1000) { + for (uintptr_t a = resource.mem.addr; + a < resource.mem.addr + resource.mem.len; a += COMMON::PAGE_SIZE) { VMM::get_instance().mmap(VMM::get_instance().get_pgd(), a, a, VMM_PAGE_READABLE | VMM_PAGE_WRITABLE); } // TODO: 多核情况下设置所有 hart // 将当前 hart 的 S 模式优先级阈值设置为 0 - IO::get_instance().write32((void *)PLIC_SPRIORITY(hart), 0); + IO::get_instance().write32((void*)PLIC_SPRIORITY(BOOT_INFO::dtb_init_hart), + 0); // 注册外部中断处理函数 - INTR::get_instance().register_interrupt_handler(INTR::INTR_S_EXTERNEL, - externel_intr); + INTR::get_instance().register_interrupt_handler(CPU::INTR_EXTERN_S, + external_intr); // 开启外部中断 CPU::WRITE_SIE(CPU::READ_SIE() | CPU::SIE_SEIE); info("plic init.\n"); @@ -80,28 +93,33 @@ int32_t PLIC::init(void) { void PLIC::set(uint8_t _no, bool _status) { // 设置 IRQ 的属性为非零,即启用 plic - IO::get_instance().write32((void *)(base_addr + _no * 4), _status); + IO::get_instance().write32((void*)(base_addr + _no * 4), _status); // TODO: 多核情况下设置所有 hart // 为当前 hart 的 S 模式设置 uart 的 enable if (_status) { IO::get_instance().write32( - (void *)PLIC_SENABLE(hart), - IO::get_instance().read32((void *)PLIC_SENABLE(hart)) | (1 << _no)); + (void*)PLIC_SENABLE(BOOT_INFO::dtb_init_hart), + IO::get_instance().read32((void*) + PLIC_SENABLE(BOOT_INFO::dtb_init_hart)) + | (1 << _no)); } else { IO::get_instance().write32( - (void *)PLIC_SENABLE(hart), - IO::get_instance().read32((void *)PLIC_SENABLE(hart)) & - ~(1 << _no)); + (void*)PLIC_SENABLE(BOOT_INFO::dtb_init_hart), + IO::get_instance().read32((void*) + PLIC_SENABLE(BOOT_INFO::dtb_init_hart)) + & ~(1 << _no)); } return; } uint8_t PLIC::get(void) { - return IO::get_instance().read32((void *)PLIC_SCLAIM(hart)); + return IO::get_instance().read32((void*) + PLIC_SCLAIM(BOOT_INFO::dtb_init_hart)); } void PLIC::done(uint8_t _no) { - IO::get_instance().write32((void *)PLIC_SCLAIM(hart), _no); + IO::get_instance().write32((void*)PLIC_SCLAIM(BOOT_INFO::dtb_init_hart), + _no); return; } diff --git a/src/arch/riscv64/intr/timer.cpp b/src/arch/riscv64/intr/timer.cpp index 365bbd797..d1b17cad5 100644 --- a/src/arch/riscv64/intr/timer.cpp +++ b/src/arch/riscv64/intr/timer.cpp @@ -14,11 +14,11 @@ * */ -#include "stdint.h" -#include "stdio.h" #include "cpu.hpp" -#include "opensbi.h" +#include "cstdint" +#include "cstdio" #include "intr.h" +#include "opensbi.h" /// timer interrupt interval /// @todo 从 dts 读取 @@ -27,7 +27,7 @@ static constexpr const uint64_t INTERVAL = 390000000 / 20; /** * @brief 设置下一次时钟 */ -void set_next(void) { +void set_next(void) { // 调用 opensbi 提供的接口设置时钟 OPENSBI::get_instance().set_timer(CPU::READ_TIME() + INTERVAL); return; @@ -36,13 +36,13 @@ void set_next(void) { /** * @brief 时钟中断 */ -void timer_intr(void) { +int32_t timer_intr(int, char**) { // 每次执行中断时设置下一次中断的时间 set_next(); - return; + return 0; } -TIMER &TIMER::get_instance(void) { +TIMER& TIMER::get_instance(void) { /// 定义全局 TIMER 对象 static TIMER timer; return timer; @@ -50,7 +50,8 @@ TIMER &TIMER::get_instance(void) { void TIMER::init(void) { // 注册中断函数 - INTR::get_instance().register_interrupt_handler(INTR::INTR_S_TIMER, timer_intr); + INTR::get_instance().register_interrupt_handler(CPU::INTR_TIMER_S, + timer_intr); // 设置初次中断 OPENSBI::get_instance().set_timer(CPU::READ_TIME()); // 开启时钟中断 diff --git a/src/arch/riscv64/link.ld b/src/arch/riscv64/link.ld index 6dfc364e8..0001413ec 100644 --- a/src/arch/riscv64/link.ld +++ b/src/arch/riscv64/link.ld @@ -1,74 +1,253 @@ /* This file is a part of Simple-XX/SimpleKernel * (https://github.com/Simple-XX/SimpleKernel). - * - * link.ld for Simple-XX/SimpleKernel. - * 链接脚本,指定生成的二进制文件的布局 */ + * Based on gnu-ld + * link.ld for Simple-XX/SimpleKernel. + * 链接脚本,指定生成的二进制文件的布局 + */ +/* Script for -z combreloc */ +/* Copyright (C) 2014-2022 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ /* 指定输出格式 */ -OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") -/* 执行输出架构 */ +OUTPUT_FORMAT( + "elf64-littleriscv", + "elf64-littleriscv", + "elf64-littleriscv" +) +/* 指定输出架构 */ OUTPUT_ARCH(riscv) /* 设置入口点 */ ENTRY(_start) /* 设置各个 section */ SECTIONS { - . = 0x80000000; - PROVIDE(kernel_start = .); + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x80200000)); /* 设置起始地址 */ - . = 0x80200000; - - PROVIDE(kernel_text_start = .); + . = SEGMENT_START("text-segment", 0x80200000); + .boot : { *(.text.boot) *(.data.boot) *(.bss.boot) } + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ifunc) + } + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .init : { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } /* 代码段 */ - .text : ALIGN(4K) { - *(.init) - *(.text*) + .text : { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) } - PROVIDE(kernel_text_end = .); - - PROVIDE(kernel_rodata_start = .); - /* 只读数据段 */ - .rodata : ALIGN(4K) { - /* 构造函数起点 */ - PROVIDE(ctors_start = .); - *(SORT_BY_INIT_PRIORITY (.init_array.*)) - *(SORT_BY_INIT_PRIORITY (.ctors.*)) - *(.init_array .ctors) - /* 构造函数终点 */ - PROVIDE(ctors_end = .); - /* 析构函数起点 */ - PROVIDE(dtors_start = .); - *(.dtor*) - /* 析构函数终点 */ - PROVIDE(dtors_end = .); - *(.rodata*) - *(.gcc_except_table) - *(.riscv.attributes) - } - PROVIDE(kernel_rodata_end = .); - - PROVIDE(kernel_data_start = .); - /* 数据段 */ - .data : ALIGN(4K) { - *(.data*) - *(.eh_frame) - *(.got*) - } - PROVIDE(kernel_data_end = .); - - PROVIDE(kernel_bss_start = .); - /* 未初始化数据段 */ - .bss : ALIGN(4K) { - *(.bss); + .fini : { + KEEP (*(SORT_NONE(.fini))) } - PROVIDE(kernel_bss_end = .); - - PROVIDE(kernel_debug_start = .); - /* 调试信息 */ - .debug : ALIGN(4K) { - *(.debug*) + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } - PROVIDE(kernel_debug_end = .); - - PROVIDE(kernel_end = .); + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { + *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) + *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) + } + .dynamic : { *(.dynamic) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : { + __DATA_BEGIN__ = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { + __SDATA_BEGIN__ = .; + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) + *(.srodata.cst2) *(.srodata .srodata.*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .sbss : { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(64 / 8); + __BSS_END__ = .; + __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, + MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1. */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions. */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2. */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2. */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions. */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3. */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF 5. */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + .debug_sup 0 : { *(.debug_sup) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } diff --git a/src/drv/CMakeLists.txt b/src/drv/CMakeLists.txt index 624d5a889..af70a1cea 100644 --- a/src/drv/CMakeLists.txt +++ b/src/drv/CMakeLists.txt @@ -1,5 +1,6 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # CMakeLists.txt for Simple-XX/SimpleKernel. # 驱动子模块的编译规则 @@ -14,11 +15,11 @@ if (SimpleKernelArch STREQUAL ia32/i386 OR SimpleKernelArch STREQUAL ia32/x86_64 aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/multiboot2 multiboot2_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/keyboard keyboard_src) set(drv_src ${tui_src} ${multiboot2_src} ${keyboard_src}) -# arm 驱动 + # arm 驱动 elseif (SimpleKernelArch STREQUAL arm) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/uart uart_src) set(drv_src ${uart_src}) -# riscv64 驱动 + # riscv64 驱动 elseif (SimpleKernelArch STREQUAL riscv64) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/opensbi opensbi_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/sbi_console sbi_console_src) @@ -26,7 +27,7 @@ elseif (SimpleKernelArch STREQUAL riscv64) set(drv_src ${opensbi_src} ${sbi_console_src} ${dtb_src}) endif () -# 添加子模块 +# 添加子模块 add_library(${PROJECT_NAME} OBJECT ${drv_src}) # 添加头文件搜索路径 diff --git a/src/drv/dtb/dtb.cpp b/src/drv/dtb/dtb.cpp index f6a91a4b6..14c081051 100644 --- a/src/drv/dtb/dtb.cpp +++ b/src/drv/dtb/dtb.cpp @@ -15,25 +15,25 @@ * */ -#include "stdint.h" -#include "stdio.h" -#include "endian.h" -#include "assert.h" -#include "common.h" +#include "dtb.h" #include "boot_info.h" +#include "cassert" +#include "common.h" +#include "cstdint" +#include "cstdio" +#include "endian.h" #include "resource.h" -#include "dtb.h" // 所有节点 -DTB::node_t DTB::nodes[MAX_NODES]; +DTB::node_t DTB::nodes[MAX_NODES]; // 节点数 -size_t DTB::node_t::count = 0; +size_t DTB::node_t::count = 0; // 所有 phandle DTB::phandle_map_t DTB::phandle_map[MAX_NODES]; // phandle 数 -size_t DTB::phandle_map_t::count = 0; +size_t DTB::phandle_map_t::count = 0; -bool DTB::path_t::operator==(const DTB::path_t *_path) { +bool DTB::path_t::operator==(const DTB::path_t* _path) { if (len != _path->len) { return false; } @@ -45,7 +45,7 @@ bool DTB::path_t::operator==(const DTB::path_t *_path) { return true; } -bool DTB::path_t::operator==(const char *_path) { +bool DTB::path_t::operator==(const char* _path) { // 路径必须以 ‘/’ 开始 if (_path[0] != '/') { return false; @@ -61,7 +61,7 @@ bool DTB::path_t::operator==(const char *_path) { return true; } -DTB::node_t *DTB::get_phandle(uint32_t _phandle) { +DTB::node_t* DTB::get_phandle(uint32_t _phandle) { // 在 phandle_map 中寻找对应的节点 for (size_t i = 0; i < phandle_map[0].count; i++) { if (phandle_map[i].phandle == _phandle) { @@ -71,7 +71,7 @@ DTB::node_t *DTB::get_phandle(uint32_t _phandle) { return nullptr; } -DTB::dt_fmt_t DTB::get_fmt(const char *_prop_name) { +DTB::dt_fmt_t DTB::get_fmt(const char* _prop_name) { // 默认为 FMT_UNKNOWN dt_fmt_t res = FMT_UNKNOWN; for (size_t i = 0; i < sizeof(props) / sizeof(dt_prop_fmt_t); i++) { @@ -83,14 +83,14 @@ DTB::dt_fmt_t DTB::get_fmt(const char *_prop_name) { return res; } -void DTB::print_attr_propenc(const iter_data_t *_iter, size_t *_cells, +void DTB::print_attr_propenc(const iter_data_t* _iter, size_t* _cells, size_t _len) { // 字节总数 - uint32_t entry_size = 0; + uint32_t entry_size = 0; // 属性长度 - uint32_t remain = _iter->prop_len; + uint32_t remain = _iter->prop_len; // 属性数据 - uint32_t *reg = _iter->prop_addr; + uint32_t* reg = _iter->prop_addr; printf("%s: ", _iter->prop_name); // 计算 @@ -126,11 +126,18 @@ void DTB::print_attr_propenc(const iter_data_t *_iter, size_t *_cells, return; } -void DTB::fill_resource(resource_t *_resource, const node_t *_node, - const prop_t *_prop) { - // 如果 _resource 名称为空则使用 _node 路径填充 +void DTB::fill_resource(resource_t* _resource, const node_t* _node, + const prop_t* _prop) { + // 如果 _resource 名称为空则使用 compatible,如果没有找到则使用 _node 路径 if (_resource->name == nullptr) { - _resource->name = _node->path.path[_node->path.len - 1]; + for (size_t i = 0; i < _node->prop_count; i++) { + if (strcmp(_node->props[i].name, "compatible") == 0) { + _resource->name = (char*)_node->props[i].addr; + } + if (_resource->name == nullptr) { + _resource->name = _node->path.path[_node->path.len - 1]; + } + } } // 内存类型 if ((_resource->type & resource_t::MEM) && (_resource->mem.len == 0)) { @@ -138,28 +145,28 @@ void DTB::fill_resource(resource_t *_resource, const node_t *_node, // resource 一般来说两者是相等的 if (_node->parent->address_cells == 1) { assert(_node->parent->size_cells == 1); - _resource->mem.addr = be32toh(((uint32_t *)_prop->addr)[0]); - _resource->mem.len = be32toh(((uint32_t *)_prop->addr)[1]); + _resource->mem.addr = be32toh(((uint32_t*)_prop->addr)[0]); + _resource->mem.len = be32toh(((uint32_t*)_prop->addr)[1]); } else if (_node->parent->address_cells == 2) { assert(_node->parent->size_cells == 2); - _resource->mem.addr = be32toh(((uint32_t *)_prop->addr)[0]) + - be32toh(((uint32_t *)_prop->addr)[1]); - _resource->mem.len = be32toh(((uint32_t *)_prop->addr)[2]) + - be32toh(((uint32_t *)_prop->addr)[3]); + _resource->mem.addr = be32toh(((uint32_t*)_prop->addr)[0]) + + be32toh(((uint32_t*)_prop->addr)[1]); + _resource->mem.len = be32toh(((uint32_t*)_prop->addr)[2]) + + be32toh(((uint32_t*)_prop->addr)[3]); } else { assert(0); } } else if (_resource->type & resource_t::INTR_NO) { - _resource->intr_no = be32toh(((uint32_t *)_prop->addr)[0]); + _resource->intr_no = be32toh(((uint32_t*)_prop->addr)[0]); } return; } -DTB::node_t *DTB::find_node_via_path(const char *_path) { - node_t *res = nullptr; +DTB::node_t* DTB::find_node_via_path(const char* _path) { + node_t* res = nullptr; // 遍历 nodes for (size_t i = 0; i < nodes[0].count; i++) { // 如果 nodes[i] 中有属性/值对符合要求 @@ -172,7 +179,7 @@ DTB::node_t *DTB::find_node_via_path(const char *_path) { } void DTB::dtb_mem_reserved(void) { - fdt_reserve_entry_t *entry = dtb_info.reserved; + fdt_reserve_entry_t* entry = dtb_info.reserved; if (entry->addr_le || entry->size_le) { // 目前没有考虑这种情况,先报错 assert(0); @@ -180,18 +187,18 @@ void DTB::dtb_mem_reserved(void) { return; } -void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), - void *_data, uintptr_t _addr) { +void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t*, void*), + void* _data, uintptr_t _addr) { // 迭代变量 iter_data_t iter; // 路径深度 - iter.path.len = 0; + iter.path.len = 0; // 数据地址 - iter.addr = (uint32_t *)_addr; + iter.addr = (uint32_t*)_addr; // 节点索引 iter.nodes_idx = 0; // 开始 flag - bool begin = true; + bool begin = true; while (1) { // @@ -204,7 +211,7 @@ void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), } case FDT_BEGIN_NODE: { // 第 len 深底的名称 - iter.path.path[iter.path.len] = (char *)(iter.addr + 1); + iter.path.path[iter.path.len] = (char*)(iter.addr + 1); // 深度+1 iter.path.len++; iter.nodes_idx = begin ? 0 : (iter.nodes_idx + 1); @@ -217,8 +224,7 @@ void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), // 跳过 type iter.addr++; // 跳过 name - iter.addr += - COMMON::ALIGN(strlen((char *)iter.addr) + 1, 4) / 4; + iter.addr += COMMON::ALIGN(strlen((char*)iter.addr) + 1, 4) / 4; break; } case FDT_END_NODE: { @@ -235,7 +241,7 @@ void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), } case FDT_PROP: { iter.prop_len = be32toh(iter.addr[1]); - iter.prop_name = (char *)(dtb_info.str + be32toh(iter.addr[2])); + iter.prop_name = (char*)(dtb_info.str + be32toh(iter.addr[2])); iter.prop_addr = iter.addr + 3; if (_cb_flags & DT_ITER_PROP) { if (_cb(&iter, _data)) { @@ -251,8 +257,8 @@ void DTB::dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), // 跳过 nameoff iter.addr++; // 跳过 data,并进行对齐 - iter.addr += COMMON::ALIGN(iter.prop_len, 4) / 4; - iter.prop_len = 0; + iter.addr += COMMON::ALIGN(iter.prop_len, 4) / 4; + iter.prop_len = 0; break; } case FDT_END: { @@ -272,7 +278,7 @@ DTB::dtb_info_t DTB::dtb_info; /* * This callback constructs tracking information about each node. */ -bool DTB::dtb_init_cb(const iter_data_t *_iter, void *) { +bool DTB::dtb_init_cb(const iter_data_t* _iter, void*) { // 索引 size_t idx = _iter->nodes_idx; // 根据类型 @@ -280,9 +286,9 @@ bool DTB::dtb_init_cb(const iter_data_t *_iter, void *) { // 开始 case FDT_BEGIN_NODE: { // 设置节点基本信息 - nodes[idx].path = _iter->path; - nodes[idx].addr = _iter->addr; - nodes[idx].depth = _iter->path.len; + nodes[idx].path = _iter->path; + nodes[idx].addr = _iter->addr; + nodes[idx].depth = _iter->path.len; // 设置默认值 nodes[idx].address_cells = 2; nodes[idx].size_cells = 2; @@ -321,15 +327,15 @@ bool DTB::dtb_init_cb(const iter_data_t *_iter, void *) { nodes[idx].phandle = be32toh(_iter->addr[3]); // 更新 phandle_map phandle_map[phandle_map[0].count].phandle = nodes[idx].phandle; - phandle_map[phandle_map[0].count].node = &nodes[idx]; + phandle_map[phandle_map[0].count].node = &nodes[idx]; phandle_map[0].count++; } // 添加属性 nodes[idx].props[nodes[idx].prop_count].name = _iter->prop_name; - nodes[idx].props[nodes[idx].prop_count].addr = - (uintptr_t)(_iter->addr + 3); - nodes[idx].props[nodes[idx].prop_count].len = - be32toh(_iter->addr[1]); + nodes[idx].props[nodes[idx].prop_count].addr + = (uintptr_t)(_iter->addr + 3); + nodes[idx].props[nodes[idx].prop_count].len + = be32toh(_iter->addr[1]); nodes[idx].prop_count++; break; } @@ -343,10 +349,10 @@ bool DTB::dtb_init_cb(const iter_data_t *_iter, void *) { return false; } -bool DTB::dtb_init_interrupt_cb(const iter_data_t *_iter, void *) { +bool DTB::dtb_init_interrupt_cb(const iter_data_t* _iter, void*) { uint8_t idx = _iter->nodes_idx; uint32_t phandle; - node_t *parent; + node_t* parent; // 设置中断父节点 if (strcmp(_iter->prop_name, "interrupt-parent") == 0) { phandle = be32toh(_iter->addr[3]); @@ -359,7 +365,7 @@ bool DTB::dtb_init_interrupt_cb(const iter_data_t *_iter, void *) { return false; } -DTB &DTB::get_instance(void) { +DTB& DTB::get_instance(void) { /// 定义全局 DTB 对象 static DTB dtb; return dtb; @@ -367,7 +373,7 @@ DTB &DTB::get_instance(void) { bool DTB::dtb_init(void) { // 头信息 - dtb_info.header = (fdt_header_t *)BOOT_INFO::boot_info_addr; + dtb_info.header = (fdt_header_t*)BOOT_INFO::boot_info_addr; // 魔数 assert(be32toh(dtb_info.header->magic) == FDT_MAGIC); // 版本 @@ -375,15 +381,15 @@ bool DTB::dtb_init(void) { // 设置大小 BOOT_INFO::boot_info_size = be32toh(dtb_info.header->totalsize); // 内存保留区 - dtb_info.reserved = - (fdt_reserve_entry_t *)(BOOT_INFO::boot_info_addr + - be32toh(dtb_info.header->off_mem_rsvmap)); + dtb_info.reserved + = (fdt_reserve_entry_t*)(BOOT_INFO::boot_info_addr + + be32toh(dtb_info.header->off_mem_rsvmap)); // 数据区 - dtb_info.data = - BOOT_INFO::boot_info_addr + be32toh(dtb_info.header->off_dt_struct); + dtb_info.data + = BOOT_INFO::boot_info_addr + be32toh(dtb_info.header->off_dt_struct); // 字符区 - dtb_info.str = - BOOT_INFO::boot_info_addr + be32toh(dtb_info.header->off_dt_strings); + dtb_info.str + = BOOT_INFO::boot_info_addr + be32toh(dtb_info.header->off_dt_strings); // 检查保留内存 dtb_mem_reserved(); // 初始化 map @@ -403,18 +409,18 @@ bool DTB::dtb_init(void) { printf("%s: ", nodes[i].props[j].name); for (size_t k = 0; k < nodes[i].props[j].len / 4; k++) { printf("0x%X ", - be32toh(((uint32_t *)nodes[i].props[j].addr)[k])); + be32toh(((uint32_t*)nodes[i].props[j].addr)[k])); } printf("\n"); } } -#undef DEBUG +# undef DEBUG #endif return true; } /// @todo 这里看起来似乎可以优化 -bool DTB::find_via_path(const char *_path, resource_t *_resource) { +bool DTB::find_via_path(const char* _path, resource_t* _resource) { // 找到节点 auto node = find_node_via_path(_path); // std::cout << node->path << std::endl; @@ -436,13 +442,14 @@ bool DTB::find_via_path(const char *_path, resource_t *_resource) { } /// @todo 这里看起来似乎可以优化 -size_t DTB::find_via_prefix(const char *_prefix, resource_t *_resource) { +size_t DTB::find_via_prefix(const char* _prefix, resource_t* _resource) { size_t res = 0; // 遍历所有节点,查找 // 由于 @ 均为最底层节点,所以直接比较最后一级即可 for (size_t i = 0; i < nodes[0].count; i++) { if (strncmp(nodes[i].path.path[nodes[i].path.len - 1], _prefix, - strlen(_prefix)) == 0) { + strlen(_prefix)) + == 0) { // 找到 reg for (size_t j = 0; j < nodes[i].prop_count; j++) { if (strcmp(nodes[i].props[j].name, "reg") == 0) { @@ -464,7 +471,7 @@ size_t DTB::find_via_prefix(const char *_prefix, resource_t *_resource) { return res; } -std::ostream &operator<<(std::ostream &_os, const DTB::iter_data_t &_iter) { +std::ostream& operator<<(std::ostream& _os, const DTB::iter_data_t& _iter) { // 输出路径 _os << _iter.path << ": "; // 根据属性类型输出 @@ -483,24 +490,24 @@ std::ostream &operator<<(std::ostream &_os, const DTB::iter_data_t &_iter) { // 32 位整数 case DTB::FMT_U32: { printf("%s: 0x%X", _iter.prop_name, - be32toh(*(uint32_t *)_iter.prop_addr)); + be32toh(*(uint32_t*)_iter.prop_addr)); break; } // 64 位整数 case DTB::FMT_U64: { printf("%s: 0x%p", _iter.prop_name, - be32toh(*(uint64_t *)_iter.prop_addr)); + be32toh(*(uint64_t*)_iter.prop_addr)); break; } // 字符串 case DTB::FMT_STRING: { - _os << _iter.prop_name << ": " << (char *)_iter.prop_addr; + _os << _iter.prop_name << ": " << (char*)_iter.prop_addr; break; } // phandle case DTB::FMT_PHANDLE: { uint32_t phandle = be32toh(_iter.addr[3]); - DTB::node_t *ref = DTB::get_instance().get_phandle(phandle); + DTB::node_t* ref = DTB::get_instance().get_phandle(phandle); if (ref != nullptr) { printf("%s: ", _iter.prop_name, ref->path.path[0]); } @@ -512,13 +519,13 @@ std::ostream &operator<<(std::ostream &_os, const DTB::iter_data_t &_iter) { // 字符串列表 case DTB::FMT_STRINGLIST: { size_t len = 0; - char *str = (char *)_iter.prop_addr; + char* str = (char*)_iter.prop_addr; _os << _iter.prop_name << ": ["; while (len < _iter.prop_len) { // 用 "" 分隔 _os << "\"" << str << "\""; len += strlen(str) + 1; - str = (char *)((uint8_t *)_iter.prop_addr + len); + str = (char*)((uint8_t*)_iter.prop_addr + len); } _os << "]"; break; @@ -526,31 +533,33 @@ std::ostream &operator<<(std::ostream &_os, const DTB::iter_data_t &_iter) { // reg,不定长的 32 位数据 case DTB::FMT_REG: { // 获取节点索引 - uint8_t idx = _iter.nodes_idx; + uint8_t idx = _iter.nodes_idx; // 全部 cells 大小 // devicetree-specification-v0.3.pdf#2.3.6 - size_t cells[] = { + size_t cells[] = { DTB::nodes[idx].parent->address_cells, DTB::nodes[idx].parent->size_cells, }; // 调用辅助函数进行输出 - DTB::get_instance().print_attr_propenc( - &_iter, cells, sizeof(cells) / sizeof(size_t)); + DTB::get_instance().print_attr_propenc(&_iter, cells, + sizeof(cells) + / sizeof(size_t)); break; } case DTB::FMT_RANGES: { // 获取节点索引 - uint8_t idx = _iter.nodes_idx; + uint8_t idx = _iter.nodes_idx; // 全部 cells 大小 // devicetree-specification-v0.3.pdf#2.3.8 - size_t cells[] = { + size_t cells[] = { DTB::nodes[idx].address_cells, DTB::nodes[idx].parent->address_cells, DTB::nodes[idx].size_cells, }; // 调用辅助函数进行输出 - DTB::get_instance().print_attr_propenc( - &_iter, cells, sizeof(cells) / sizeof(size_t)); + DTB::get_instance().print_attr_propenc(&_iter, cells, + sizeof(cells) + / sizeof(size_t)); break; } default: { @@ -561,7 +570,7 @@ std::ostream &operator<<(std::ostream &_os, const DTB::iter_data_t &_iter) { return _os; } -std::ostream &operator<<(std::ostream &_os, const DTB::path_t &_path) { +std::ostream& operator<<(std::ostream& _os, const DTB::path_t& _path) { if (_path.len == 1) { _os << "/"; } @@ -576,13 +585,13 @@ namespace BOOT_INFO { // 地址 uintptr_t boot_info_addr; // 长度 -size_t boot_info_size; +size_t boot_info_size; // 启动核 -size_t dtb_init_hart; +size_t dtb_init_hart; -bool inited = false; +bool inited = false; -bool init(void) { +bool init(void) { auto res = DTB::get_instance().dtb_init(); if (inited == false) { inited = true; @@ -601,7 +610,7 @@ resource_t get_memory(void) { return resource; } -size_t find_via_prefix(const char *_prefix, resource_t *_resource) { +size_t find_via_prefix(const char* _prefix, resource_t* _resource) { return DTB::get_instance().find_via_prefix(_prefix, _resource); } @@ -620,4 +629,5 @@ resource_t get_plic(void) { assert(DTB::get_instance().find_via_prefix("plic@", &resource) == 1); return resource; } -}; // namespace BOOT_INFO + +}; // namespace BOOT_INFO diff --git a/src/drv/dtb/include/dtb.h b/src/drv/dtb/include/dtb.h index 383d27987..52d4e9daa 100644 --- a/src/drv/dtb/include/dtb.h +++ b/src/drv/dtb/include/dtb.h @@ -15,15 +15,15 @@ * */ -#ifndef _DTB_H_ -#define _DTB_H_ +#ifndef SIMPLEKERNEL_DTB_H +#define SIMPLEKERNEL_DTB_H -#include "stdint.h" -#include "stdbool.h" #include "boot_info.h" -#include "resource.h" +#include "cstdbool" +#include "cstdint" #include "endian.h" #include "iostream" +#include "resource.h" /// @see devicetree-specification-v0.3.pdf /// @see https://e-mailky.github.io/2016-12-06-dts-introduce @@ -40,19 +40,19 @@ class DTB { /// node 开始标记 static constexpr const uint32_t FDT_BEGIN_NODE = 0x1; /// node 结束标记 - static constexpr const uint32_t FDT_END_NODE = 0x2; + static constexpr const uint32_t FDT_END_NODE = 0x2; /// 属性开始标记 - static constexpr const uint32_t FDT_PROP = 0x3; + static constexpr const uint32_t FDT_PROP = 0x3; /// 无效标记 - static constexpr const uint32_t FDT_NOP = 0x4; + static constexpr const uint32_t FDT_NOP = 0x4; /// 数据区结束标记 - static constexpr const uint32_t FDT_END = 0x9; + static constexpr const uint32_t FDT_END = 0x9; /// @see devicetree-specification-v0.3.pdf#5.1 /// 魔数 - static constexpr const uint32_t FDT_MAGIC = 0xD00DFEED; + static constexpr const uint32_t FDT_MAGIC = 0xD00DFEED; /// 版本 17 - static constexpr const uint32_t FDT_VERSION = 0x11; + static constexpr const uint32_t FDT_VERSION = 0x11; /** * @brief fdt 格式头 @@ -114,20 +114,20 @@ class DTB { /// 最大节点数 static constexpr const size_t MAX_NODES = 128; /// 最大属性数 - static constexpr const size_t PROP_MAX = 16; + static constexpr const size_t PROP_MAX = 16; /** * @brief dtb 信息 */ struct dtb_info_t { /// dtb 头 - fdt_header_t *header; + fdt_header_t* header; /// 保留区 - fdt_reserve_entry_t *reserved; + fdt_reserve_entry_t* reserved; /// 数据区 - uintptr_t data; + uintptr_t data; /// 字符区 - uintptr_t str; + uintptr_t str; }; /** @@ -135,11 +135,11 @@ class DTB { */ struct prop_t { /// 属性名 - char *name; + char* name; /// 属性地址 uintptr_t addr; /// 属性长度 - size_t len; + size_t len; }; /** @@ -147,7 +147,7 @@ class DTB { */ struct path_t { /// 当前路径 - char *path[MAX_DEPTH]; + char* path[MAX_DEPTH]; /// 长度 size_t len; /** @@ -156,8 +156,8 @@ class DTB { * @return true 相同 * @return false 不同 */ - bool operator==(const path_t *_path); - bool operator==(const char *_path); + bool operator==(const path_t* _path); + bool operator==(const char* _path); }; /** @@ -165,31 +165,31 @@ class DTB { */ struct node_t { /// 节点路径 - path_t path; + path_t path; /// 节点地址 - uint32_t *addr; + uint32_t* addr; /// 父节点 - node_t *parent; + node_t* parent; /// 中断父节点 - node_t *interrupt_parent; + node_t* interrupt_parent; /// 1 cell == 4 bytes /// 地址长度 单位为 bytes - uint32_t address_cells; + uint32_t address_cells; /// 长度长度 单位为 bytes - uint32_t size_cells; + uint32_t size_cells; /// 中断长度 单位为 bytes - uint32_t interrupt_cells; - uint32_t phandle; + uint32_t interrupt_cells; + uint32_t phandle; /// 路径深度 - uint8_t depth; + uint8_t depth; /// 属性 - prop_t props[PROP_MAX]; + prop_t props[PROP_MAX]; /// 属性数 - size_t prop_count; + size_t prop_count; /// 节点数 static size_t count; /// 查找节点中的键值对 - bool find(const char *_prop_name, const char *_val); + bool find(const char* _prop_name, const char* _val); }; /** @@ -197,19 +197,19 @@ class DTB { */ struct iter_data_t { /// 路径,不包括节点名 - path_t path; + path_t path; /// 节点地址 - uint32_t *addr; + uint32_t* addr; /// 节点类型 - uint32_t type; + uint32_t type; /// 如果节点类型为 PROP, 保存节点属性名 - char *prop_name; + char* prop_name; /// 如果节点类型为 PROP, 保存属性长度 单位为 byte - uint32_t prop_len; + uint32_t prop_len; /// 如果节点类型为 PROP, 保存属性地址 - uint32_t *prop_addr; + uint32_t* prop_addr; /// 在 nodes 数组的下标 - uint8_t nodes_idx; + uint8_t nodes_idx; }; // 部分属性及格式 @@ -244,7 +244,7 @@ class DTB { */ struct dt_prop_fmt_t { /// 属性名 - char *prop_name; + char* prop_name; /// 格式 enum dt_fmt_t fmt; }; @@ -254,26 +254,26 @@ class DTB { * @see 格式信息请查看 devicetree-specification-v0.3#2.3,#2.4 等部分 */ static constexpr const dt_prop_fmt_t props[] = { - {.prop_name = (char *)"", .fmt = FMT_EMPTY}, - {.prop_name = (char *)"compatible", .fmt = FMT_STRINGLIST}, - {.prop_name = (char *)"model", .fmt = FMT_STRING}, - {.prop_name = (char *)"phandle", .fmt = FMT_U32}, - {.prop_name = (char *)"status", .fmt = FMT_STRING}, - {.prop_name = (char *)"#address-cells", .fmt = FMT_U32}, - {.prop_name = (char *)"#size-cells", .fmt = FMT_U32}, - {.prop_name = (char *)"#interrupt-cells", .fmt = FMT_U32}, - {.prop_name = (char *)"reg", .fmt = FMT_REG}, - {.prop_name = (char *)"virtual-reg", .fmt = FMT_U32}, - {.prop_name = (char *)"ranges", .fmt = FMT_RANGES}, - {.prop_name = (char *)"dma-ranges", .fmt = FMT_RANGES}, - {.prop_name = (char *)"name", .fmt = FMT_STRING}, - {.prop_name = (char *)"device_type", .fmt = FMT_STRING}, - {.prop_name = (char *)"interrupts", .fmt = FMT_U32}, - {.prop_name = (char *)"interrupt-parent", .fmt = FMT_PHANDLE}, - {.prop_name = (char *)"interrupt-controller", .fmt = FMT_EMPTY}, - {.prop_name = (char *)"value", .fmt = FMT_U32}, - {.prop_name = (char *)"offset", .fmt = FMT_U32}, - {.prop_name = (char *)"regmap", .fmt = FMT_U32}, + { .prop_name = (char*)"", .fmt = FMT_EMPTY}, + { .prop_name = (char*)"compatible", .fmt = FMT_STRINGLIST}, + { .prop_name = (char*)"model", .fmt = FMT_STRING}, + { .prop_name = (char*)"phandle", .fmt = FMT_U32}, + { .prop_name = (char*)"status", .fmt = FMT_STRING}, + { .prop_name = (char*)"#address-cells", .fmt = FMT_U32}, + { .prop_name = (char*)"#size-cells", .fmt = FMT_U32}, + { .prop_name = (char*)"#interrupt-cells", .fmt = FMT_U32}, + { .prop_name = (char*)"reg", .fmt = FMT_REG}, + { .prop_name = (char*)"virtual-reg", .fmt = FMT_U32}, + { .prop_name = (char*)"ranges", .fmt = FMT_RANGES}, + { .prop_name = (char*)"dma-ranges", .fmt = FMT_RANGES}, + { .prop_name = (char*)"name", .fmt = FMT_STRING}, + { .prop_name = (char*)"device_type", .fmt = FMT_STRING}, + { .prop_name = (char*)"interrupts", .fmt = FMT_U32}, + { .prop_name = (char*)"interrupt-parent", .fmt = FMT_PHANDLE}, + {.prop_name = (char*)"interrupt-controller", .fmt = FMT_EMPTY}, + { .prop_name = (char*)"value", .fmt = FMT_U32}, + { .prop_name = (char*)"offset", .fmt = FMT_U32}, + { .prop_name = (char*)"regmap", .fmt = FMT_U32}, }; /** @@ -281,29 +281,29 @@ class DTB { * @param _prop_name 要查找的属性 * @return dt_fmt_t 在 dt_fmt_t 中的索引 */ - dt_fmt_t get_fmt(const char *_prop_name); + dt_fmt_t get_fmt(const char* _prop_name); /** * @brief phandles 与 node 的映射关系 */ struct phandle_map_t { - uint32_t phandle; - node_t *node; + uint32_t phandle; + node_t* node; /// phandle 数量 static size_t count; }; /// dtb 信息 - static dtb_info_t dtb_info; + static dtb_info_t dtb_info; /// 节点数组 - static node_t nodes[MAX_NODES]; + static node_t nodes[MAX_NODES]; /// phandle 数组 static phandle_map_t phandle_map[MAX_NODES]; /** * @brief 输出 reserved 内存 */ - void dtb_mem_reserved(void); + void dtb_mem_reserved(void); /** * @brief 迭代函数 @@ -312,15 +312,15 @@ class DTB { * @param _data 要传递的数据 * @param _addr dtb 数据地址 */ - void dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t *, void *), - void *_data, uintptr_t _addr = dtb_info.data); + void dtb_iter(uint8_t _cb_flags, bool (*_cb)(const iter_data_t*, void*), + void* _data, uintptr_t _addr = dtb_info.data); /** * @brief 查找 phandle 映射 * @param _phandle 要查找的 phandle * @return node_t* _phandle 指向的节点 */ - node_t *get_phandle(uint32_t _phandle); + node_t* get_phandle(uint32_t _phandle); /** * @brief 初始化节点 @@ -329,7 +329,7 @@ class DTB { * @return true 成功 * @return false 失败 */ - static bool dtb_init_cb(const iter_data_t *_iter, void *_data); + static bool dtb_init_cb(const iter_data_t* _iter, void* _data); /** * @brief 初始化中断信息 @@ -338,7 +338,7 @@ class DTB { * @return true 成功 * @return false 失败 */ - static bool dtb_init_interrupt_cb(const iter_data_t *_iter, void *_data); + static bool dtb_init_interrupt_cb(const iter_data_t* _iter, void* _data); /** * @brief 输出不定长度的数据 @@ -347,8 +347,8 @@ class DTB { * @param _len 长度 * @todo 补充说明 */ - void print_attr_propenc(const iter_data_t *_iter, size_t *_cells, - size_t _len); + void + print_attr_propenc(const iter_data_t* _iter, size_t* _cells, size_t _len); /** * @brief 填充 resource_t @@ -356,38 +356,39 @@ class DTB { * @param _node 源节点 * @param _prop 填充的数据 */ - void fill_resource(resource_t *_resource, const node_t *_node, - const prop_t *_prop); + void fill_resource(resource_t* _resource, const node_t* _node, + const prop_t* _prop); /** * @brief 通过路径寻找节点 * @param _path 路径 * @return node_t* 找到的节点 */ - node_t *find_node_via_path(const char *_path); + node_t* find_node_via_path(const char* _path); protected: + public: // 用于控制处理哪些属性 /// 处理节点开始 static constexpr const uint8_t DT_ITER_BEGIN_NODE = 0x01; /// 处理节点结束 - static constexpr const uint8_t DT_ITER_END_NODE = 0x02; + static constexpr const uint8_t DT_ITER_END_NODE = 0x02; /// 处理节点属性 - static constexpr const uint8_t DT_ITER_PROP = 0x04; + static constexpr const uint8_t DT_ITER_PROP = 0x04; /** * @brief 获取单例 * @return DTB& 静态对象 */ - static DTB &get_instance(void); + static DTB& get_instance(void); /** * @brief 初始化 * @return true 成功 * @return false 失败 */ - bool dtb_init(void); + bool dtb_init(void); /** * @brief 根据路径查找节点,返回使用的资源 @@ -396,7 +397,7 @@ class DTB { * @return true 成功 * @return false 失败 */ - bool find_via_path(const char *_path, resource_t *_resource); + bool find_via_path(const char* _path, resource_t* _resource); /** * @brief 根据节点名进行前缀查找 @@ -405,7 +406,7 @@ class DTB { * @return size_t _resource 长度 * @note 根据节点 @ 前的名称查找,可能返回多个 resource */ - size_t find_via_prefix(const char *_prefix, resource_t *_resource); + size_t find_via_prefix(const char* _prefix, resource_t* _resource); /** * @brief iter 输出 @@ -413,20 +414,15 @@ class DTB { * @param _iter 要输出的 iter * @return std::ostream& 输出流 */ - friend std::ostream &operator<<(std::ostream &_os, - const iter_data_t &_iter); + friend std::ostream& + operator<<(std::ostream& _os, const iter_data_t& _iter); /** * @brief 路径输出 * @param _os 输出流 * @param _path 要输出的 path * @return std::ostream& 输出流 */ - friend std::ostream &operator<<(std::ostream &_os, const path_t &_path); + friend std::ostream& operator<<(std::ostream& _os, const path_t& _path); }; -namespace BOOT_INFO { -/// 保存 sbi 传递的启动核 -extern "C" size_t dtb_init_hart; -}; // namespace BOOT_INFO - -#endif /* _DTB_H_ */ +#endif /* SIMPLEKERNEL_DTB_H */ diff --git a/src/drv/keyboard/include/keyboard.h b/src/drv/keyboard/include/keyboard.h index c9aac3162..eecd1b0c7 100644 --- a/src/drv/keyboard/include/keyboard.h +++ b/src/drv/keyboard/include/keyboard.h @@ -18,7 +18,7 @@ #ifndef _KEYBOARD_H_ #define _KEYBOARD_H_ -#include "stdint.h" +#include "cstdint" #include "intr.h" /** @@ -27,27 +27,27 @@ class KEYBOARD { private: /// 键盘缓冲区大小 - static constexpr const uint32_t KB_BUFSIZE = 128; + static constexpr const uint32_t KB_BUFSIZE = 128; - static constexpr const uint32_t KB_DATA = 0x60; - static constexpr const uint32_t KB_WRITE = 0x60; - static constexpr const uint32_t KB_STATUS = 0x64; - static constexpr const uint32_t KB_CMD = 0x64; + static constexpr const uint32_t KB_DATA = 0x60; + static constexpr const uint32_t KB_WRITE = 0x60; + static constexpr const uint32_t KB_STATUS = 0x64; + static constexpr const uint32_t KB_CMD = 0x64; /// 特殊键的扫描码 - static constexpr const uint32_t KB_BACKSPACE = 0x0E; - static constexpr const uint32_t KB_ENTER = 0x1C; - static constexpr const uint32_t KB_TAB = 0x0F; - static constexpr const uint32_t KB_ESC = 0x01; - static constexpr const uint32_t KB_SHIFT_L = 0x2A; - static constexpr const uint32_t KB_SHIFT_R = 0x36; - static constexpr const uint32_t KB_ALT_L = 0x38; - static constexpr const uint32_t KB_CAPS_LOCK = 0x3A; - static constexpr const uint32_t KB_CTRL_L = 0x1D; - static constexpr const uint32_t KB_NUM_LOCK = 0x45; + static constexpr const uint32_t KB_BACKSPACE = 0x0E; + static constexpr const uint32_t KB_ENTER = 0x1C; + static constexpr const uint32_t KB_TAB = 0x0F; + static constexpr const uint32_t KB_ESC = 0x01; + static constexpr const uint32_t KB_SHIFT_L = 0x2A; + static constexpr const uint32_t KB_SHIFT_R = 0x36; + static constexpr const uint32_t KB_ALT_L = 0x38; + static constexpr const uint32_t KB_CAPS_LOCK = 0x3A; + static constexpr const uint32_t KB_CTRL_L = 0x1D; + static constexpr const uint32_t KB_NUM_LOCK = 0x45; /// Number of columns in keyma - static constexpr const uint32_t MAP_COLS = 3; + static constexpr const uint32_t MAP_COLS = 3; /// Number of scan codes (rows in keymap) static constexpr const uint32_t NR_SCAN_CODES = 0x80; static constexpr const uint32_t SC_MAX = NR_SCAN_CODES * MAP_COLS; @@ -58,164 +58,164 @@ class KEYBOARD { static constexpr const uint32_t RELEASED_MASK = 0x80; /// Normal function keys - static constexpr const uint32_t FLAG_EXT = 0x00; + static constexpr const uint32_t FLAG_EXT = 0x00; /// Special keys /// Esc - static constexpr const uint32_t ESC = (0x01 & FLAG_EXT); + static constexpr const uint32_t ESC = (0x01 & FLAG_EXT); /// Tab - static constexpr const uint32_t TAB = (0x02 & FLAG_EXT); + static constexpr const uint32_t TAB = (0x02 & FLAG_EXT); /// Enter - static constexpr const uint32_t ENTER = (0x03 & FLAG_EXT); + static constexpr const uint32_t ENTER = (0x03 & FLAG_EXT); /// BackSpace - static constexpr const uint32_t BACKSPACE = (0x04 & FLAG_EXT); + static constexpr const uint32_t BACKSPACE = (0x04 & FLAG_EXT); /// L GUI - static constexpr const uint32_t GUI_L = (0x05 & FLAG_EXT); + static constexpr const uint32_t GUI_L = (0x05 & FLAG_EXT); /// R GUI - static constexpr const uint32_t GUI_R = (0x06 & FLAG_EXT); + static constexpr const uint32_t GUI_R = (0x06 & FLAG_EXT); /// APPS - static constexpr const uint32_t APPS = (0x07 & FLAG_EXT); + static constexpr const uint32_t APPS = (0x07 & FLAG_EXT); /// Shift, Ctrl, Alt /// L Shift - static constexpr const uint32_t SHIFT_L = (0x08 & FLAG_EXT); + static constexpr const uint32_t SHIFT_L = (0x08 & FLAG_EXT); /// R Shift - static constexpr const uint32_t SHIFT_R = (0x09 & FLAG_EXT); + static constexpr const uint32_t SHIFT_R = (0x09 & FLAG_EXT); /// L Ctrl - static constexpr const uint32_t CTRL_L = (0x0A & FLAG_EXT); + static constexpr const uint32_t CTRL_L = (0x0A & FLAG_EXT); /// R Ctrl - static constexpr const uint32_t CTRL_R = (0x0B & FLAG_EXT); + static constexpr const uint32_t CTRL_R = (0x0B & FLAG_EXT); /// L Alt - static constexpr const uint32_t ALT_L = (0x0C & FLAG_EXT); + static constexpr const uint32_t ALT_L = (0x0C & FLAG_EXT); /// R Alt - static constexpr const uint32_t ALT_R = (0x0D & FLAG_EXT); + static constexpr const uint32_t ALT_R = (0x0D & FLAG_EXT); /// Lock keys /// Caps Lock - static constexpr const uint32_t CAPS_LOCK = (0x0E & FLAG_EXT); + static constexpr const uint32_t CAPS_LOCK = (0x0E & FLAG_EXT); /// Number Lock - static constexpr const uint32_t NUM_LOCK = (0x0F & FLAG_EXT); + static constexpr const uint32_t NUM_LOCK = (0x0F & FLAG_EXT); /// Scroll Lock - static constexpr const uint32_t SCROLL_LOCK = (0x10 & FLAG_EXT); + static constexpr const uint32_t SCROLL_LOCK = (0x10 & FLAG_EXT); /// Function keys /// F1 - static constexpr const uint32_t F1 = (0x11 & FLAG_EXT); + static constexpr const uint32_t F1 = (0x11 & FLAG_EXT); /// F2 - static constexpr const uint32_t F2 = (0x12 & FLAG_EXT); + static constexpr const uint32_t F2 = (0x12 & FLAG_EXT); /// F3 - static constexpr const uint32_t F3 = (0x13 & FLAG_EXT); + static constexpr const uint32_t F3 = (0x13 & FLAG_EXT); /// F4 - static constexpr const uint32_t F4 = (0x14 & FLAG_EXT); + static constexpr const uint32_t F4 = (0x14 & FLAG_EXT); /// F5 - static constexpr const uint32_t F5 = (0x15 & FLAG_EXT); + static constexpr const uint32_t F5 = (0x15 & FLAG_EXT); /// F6 - static constexpr const uint32_t F6 = (0x16 & FLAG_EXT); + static constexpr const uint32_t F6 = (0x16 & FLAG_EXT); /// F7 - static constexpr const uint32_t F7 = (0x17 & FLAG_EXT); + static constexpr const uint32_t F7 = (0x17 & FLAG_EXT); /// F8 - static constexpr const uint32_t F8 = (0x18 & FLAG_EXT); + static constexpr const uint32_t F8 = (0x18 & FLAG_EXT); /// F9 - static constexpr const uint32_t F9 = (0x19 & FLAG_EXT); + static constexpr const uint32_t F9 = (0x19 & FLAG_EXT); /// F10 - static constexpr const uint32_t F10 = (0x1A & FLAG_EXT); + static constexpr const uint32_t F10 = (0x1A & FLAG_EXT); /// F11 - static constexpr const uint32_t F11 = (0x1B & FLAG_EXT); + static constexpr const uint32_t F11 = (0x1B & FLAG_EXT); /// F12 - static constexpr const uint32_t F12 = (0x1C & FLAG_EXT); + static constexpr const uint32_t F12 = (0x1C & FLAG_EXT); /// Control Pad /// Print Screen - static constexpr const uint32_t PRINTSCREEN = (0x1D & FLAG_EXT); + static constexpr const uint32_t PRINTSCREEN = (0x1D & FLAG_EXT); /// Pause/Break - static constexpr const uint32_t PAUSEBREAK = (0x1E & FLAG_EXT); + static constexpr const uint32_t PAUSEBREAK = (0x1E & FLAG_EXT); /// Insert - static constexpr const uint32_t INSERT = (0x1F & FLAG_EXT); + static constexpr const uint32_t INSERT = (0x1F & FLAG_EXT); /// Delete - static constexpr const uint32_t DELETE = (0x20 & FLAG_EXT); + static constexpr const uint32_t DELETE = (0x20 & FLAG_EXT); /// Home - static constexpr const uint32_t HOME = (0x21 & FLAG_EXT); + static constexpr const uint32_t HOME = (0x21 & FLAG_EXT); /// End - static constexpr const uint32_t END = (0x22 & FLAG_EXT); + static constexpr const uint32_t END = (0x22 & FLAG_EXT); /// Page Up - static constexpr const uint32_t PAGEUP = (0x23 & FLAG_EXT); + static constexpr const uint32_t PAGEUP = (0x23 & FLAG_EXT); /// Page Down - static constexpr const uint32_t PAGEDOWN = (0x24 & FLAG_EXT); + static constexpr const uint32_t PAGEDOWN = (0x24 & FLAG_EXT); /// Up - static constexpr const uint32_t UP = (0x25 & FLAG_EXT); + static constexpr const uint32_t UP = (0x25 & FLAG_EXT); /// Down - static constexpr const uint32_t DOWN = (0x26 & FLAG_EXT); + static constexpr const uint32_t DOWN = (0x26 & FLAG_EXT); /// Left - static constexpr const uint32_t LEFT = (0x27 & FLAG_EXT); + static constexpr const uint32_t LEFT = (0x27 & FLAG_EXT); /// Right - static constexpr const uint32_t RIGHT = (0x28 & FLAG_EXT); + static constexpr const uint32_t RIGHT = (0x28 & FLAG_EXT); /// ACPI keys /// Power - static constexpr const uint32_t POWER = (0x29 & FLAG_EXT); + static constexpr const uint32_t POWER = (0x29 & FLAG_EXT); /// Sleep - static constexpr const uint32_t SLEEP = (0x2A & FLAG_EXT); + static constexpr const uint32_t SLEEP = (0x2A & FLAG_EXT); /// Wake Up - static constexpr const uint32_t WAKE = (0x2B & FLAG_EXT); + static constexpr const uint32_t WAKE = (0x2B & FLAG_EXT); /// Num Pad /// / - static constexpr const uint32_t PAD_SLASH = (0x2C & FLAG_EXT); + static constexpr const uint32_t PAD_SLASH = (0x2C & FLAG_EXT); /// * - static constexpr const uint32_t PAD_STAR = (0x2D & FLAG_EXT); + static constexpr const uint32_t PAD_STAR = (0x2D & FLAG_EXT); /// - - static constexpr const uint32_t PAD_MINUS = (0x2E & FLAG_EXT); + static constexpr const uint32_t PAD_MINUS = (0x2E & FLAG_EXT); /// & - static constexpr const uint32_t PAD_PLUS = (0x2F & FLAG_EXT); + static constexpr const uint32_t PAD_PLUS = (0x2F & FLAG_EXT); /// Enter - static constexpr const uint32_t PAD_ENTER = (0x30 & FLAG_EXT); + static constexpr const uint32_t PAD_ENTER = (0x30 & FLAG_EXT); /// . - static constexpr const uint32_t PAD_DOT = (0x31 & FLAG_EXT); + static constexpr const uint32_t PAD_DOT = (0x31 & FLAG_EXT); /// 0 - static constexpr const uint32_t PAD_0 = (0x32 & FLAG_EXT); + static constexpr const uint32_t PAD_0 = (0x32 & FLAG_EXT); /// 1 - static constexpr const uint32_t PAD_1 = (0x33 & FLAG_EXT); + static constexpr const uint32_t PAD_1 = (0x33 & FLAG_EXT); /// 2 - static constexpr const uint32_t PAD_2 = (0x34 & FLAG_EXT); + static constexpr const uint32_t PAD_2 = (0x34 & FLAG_EXT); /// 3 - static constexpr const uint32_t PAD_3 = (0x35 & FLAG_EXT); + static constexpr const uint32_t PAD_3 = (0x35 & FLAG_EXT); /// 4 - static constexpr const uint32_t PAD_4 = (0x36 & FLAG_EXT); + static constexpr const uint32_t PAD_4 = (0x36 & FLAG_EXT); /// 5 - static constexpr const uint32_t PAD_5 = (0x37 & FLAG_EXT); + static constexpr const uint32_t PAD_5 = (0x37 & FLAG_EXT); /// 6 - static constexpr const uint32_t PAD_6 = (0x38 & FLAG_EXT); + static constexpr const uint32_t PAD_6 = (0x38 & FLAG_EXT); /// 7 - static constexpr const uint32_t PAD_7 = (0x39 & FLAG_EXT); + static constexpr const uint32_t PAD_7 = (0x39 & FLAG_EXT); /// 8 - static constexpr const uint32_t PAD_8 = (0x3A & FLAG_EXT); + static constexpr const uint32_t PAD_8 = (0x3A & FLAG_EXT); /// 9 - static constexpr const uint32_t PAD_9 = (0x3B & FLAG_EXT); + static constexpr const uint32_t PAD_9 = (0x3B & FLAG_EXT); /// Up - static constexpr const uint32_t PAD_UP = PAD_8; + static constexpr const uint32_t PAD_UP = PAD_8; /// Down - static constexpr const uint32_t PAD_DOWN = PAD_2; + static constexpr const uint32_t PAD_DOWN = PAD_2; /// Left - static constexpr const uint32_t PAD_LEFT = PAD_4; + static constexpr const uint32_t PAD_LEFT = PAD_4; /// Right - static constexpr const uint32_t PAD_RIGHT = PAD_6; + static constexpr const uint32_t PAD_RIGHT = PAD_6; /// Home - static constexpr const uint32_t PAD_HOME = PAD_7; + static constexpr const uint32_t PAD_HOME = PAD_7; /// End - static constexpr const uint32_t PAD_END = PAD_1; + static constexpr const uint32_t PAD_END = PAD_1; /// Page Up - static constexpr const uint32_t PAD_PAGEUP = PAD_9; + static constexpr const uint32_t PAD_PAGEUP = PAD_9; /// Page Down - static constexpr const uint32_t PAD_PAGEDOWN = PAD_3; + static constexpr const uint32_t PAD_PAGEDOWN = PAD_3; /// Ins - static constexpr const uint32_t PAD_INS = PAD_0; + static constexpr const uint32_t PAD_INS = PAD_0; /// Middle key - static constexpr const uint32_t PAD_MID = PAD_5; + static constexpr const uint32_t PAD_MID = PAD_5; /// Del - static constexpr const uint32_t PAD_DEL = PAD_DOT; + static constexpr const uint32_t PAD_DEL = PAD_DOT; /// 键盘映射 - static constexpr const uint8_t keymap[NR_SCAN_CODES * MAP_COLS] = { + static constexpr const uint8_t keymap[NR_SCAN_CODES * MAP_COLS] = { /* scan-code !Shift Shift E0 XX */ /* ==================================================================== @@ -612,6 +612,7 @@ class KEYBOARD { bool alt; protected: + public: KEYBOARD(void); ~KEYBOARD(void); @@ -620,26 +621,26 @@ class KEYBOARD { * @brief 获取单例 * @return KEYBOARD& 静态对象 */ - static KEYBOARD &get_instance(void); + static KEYBOARD& get_instance(void); /** * @brief 初始化 * @return int32_t 成功返回 0 */ - int32_t init(void); + int32_t init(void); /** * @brief 从键盘读 * @return uint8_t 读到的数据 */ - uint8_t read(void); + uint8_t read(void); /** * @brief 设置键盘中断处理函数 * @param _h 处理函数 * @return int32_t 设置成功返回 0 */ - int32_t set_handle(INTR::interrupt_handler_t _h); + int32_t set_handle(INTR::interrupt_handler_t _h); }; #endif /* _KEYBOARD_H_ */ diff --git a/src/drv/keyboard/keyboard.cpp b/src/drv/keyboard/keyboard.cpp index 3813d8f26..1eb116afb 100644 --- a/src/drv/keyboard/keyboard.cpp +++ b/src/drv/keyboard/keyboard.cpp @@ -15,16 +15,14 @@ * */ -#include "stddef.h" -#include "stdbool.h" -#include "io.h" -#include "stdio.h" #include "keyboard.h" +#include "cstdio" +#include "io.h" /** * @brief 默认处理函数 */ -static void default_keyboard_handle(INTR::intr_context_t *) { +static void default_keyboard_handle(INTR::intr_context_t*) { KEYBOARD::get_instance().read(); return; } @@ -113,7 +111,7 @@ uint8_t KEYBOARD::read(void) { return letter; } -KEYBOARD &KEYBOARD::get_instance(void) { +KEYBOARD& KEYBOARD::get_instance(void) { /// 定义全局 KEYBOARD 对象 static KEYBOARD keyboard; return keyboard; diff --git a/src/drv/multiboot2/include/multiboot2.h b/src/drv/multiboot2/include/multiboot2.h index 22de1d9b7..62b077ad3 100644 --- a/src/drv/multiboot2/include/multiboot2.h +++ b/src/drv/multiboot2/include/multiboot2.h @@ -14,12 +14,12 @@ * */ -#ifndef _MULTIBOOT2_H_ -#define _MULTIBOOT2_H_ +#ifndef SIMPLEKERNEL_MULTIBOOT2_H +#define SIMPLEKERNEL_MULTIBOOT2_H -#include "stdint.h" -#include "stdbool.h" #include "boot_info.h" +#include "cstdbool" +#include "cstdint" /// @see Multiboot2 Specification version 2.0.pdf // 启动后,在 32 位内核进入点,机器状态如下: @@ -39,26 +39,26 @@ class MULTIBOOT2 { private: /* How many bytes from the start of the file we search for the header. */ - static constexpr const uint32_t MULTIBOOT_SEARCH = 32768; - static constexpr const uint32_t MULTIBOOT_HEADER_ALIGN = 8; + static constexpr const uint32_t MULTIBOOT_SEARCH = 32768; + static constexpr const uint32_t MULTIBOOT_HEADER_ALIGN = 8; /* The magic field should contain this. */ - static constexpr const uint32_t MULTIBOOT2_HEADER_MAGIC = 0xe85250d6; + static constexpr const uint32_t MULTIBOOT2_HEADER_MAGIC = 0xe85250d6; /* This should be in %eax. */ static constexpr const uint32_t MULTIBOOT2_BOOTLOADER_MAGIC = 0x36d76289; /* Alignment of multiboot modules. */ - static constexpr const uint32_t MULTIBOOT_MOD_ALIGN = 0x00001000; + static constexpr const uint32_t MULTIBOOT_MOD_ALIGN = 0x00001000; /* Alignment of the multiboot info structure. */ - static constexpr const uint32_t MULTIBOOT_INFO_ALIGN = 0x00000008; + static constexpr const uint32_t MULTIBOOT_INFO_ALIGN = 0x00000008; /* Flags set in the 'flags' member of the multiboot header. */ - static constexpr const uint32_t MULTIBOOT_TAG_ALIGN = 8; - static constexpr const uint32_t MULTIBOOT_TAG_TYPE_END = 0; - static constexpr const uint32_t MULTIBOOT_TAG_TYPE_CMDLINE = 1; + static constexpr const uint32_t MULTIBOOT_TAG_ALIGN = 8; + static constexpr const uint32_t MULTIBOOT_TAG_TYPE_END = 0; + static constexpr const uint32_t MULTIBOOT_TAG_TYPE_CMDLINE = 1; static constexpr const uint32_t MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME = 2; static constexpr const uint32_t MULTIBOOT_TAG_TYPE_MODULE = 3; static constexpr const uint32_t MULTIBOOT_TAG_TYPE_BASIC_MEMINFO = 4; @@ -80,33 +80,33 @@ class MULTIBOOT2 { static constexpr const uint32_t MULTIBOOT_TAG_TYPE_EFI64_IH = 20; static constexpr const uint32_t MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR = 21; - static constexpr const uint32_t MULTIBOOT_HEADER_TAG_END = 0; - static constexpr const uint32_t MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST = - 1; + static constexpr const uint32_t MULTIBOOT_HEADER_TAG_END = 0; + static constexpr const uint32_t MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST + = 1; static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ADDRESS = 2; static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS = 3; static constexpr const uint32_t MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS = 4; static constexpr const uint32_t MULTIBOOT_HEADER_TAG_FRAMEBUFFER = 5; static constexpr const uint32_t MULTIBOOT_HEADER_TAG_MODULE_ALIGN = 6; static constexpr const uint32_t MULTIBOOT_HEADER_TAG_EFI_BS = 7; - static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 = - 8; - static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 = - 9; + static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 + = 8; + static constexpr const uint32_t MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 + = 9; static constexpr const uint32_t MULTIBOOT_HEADER_TAG_RELOCATABLE = 10; - static constexpr const uint32_t MULTIBOOT_ARCHITECTURE_I386 = 0; - static constexpr const uint32_t MULTIBOOT_ARCHITECTURE_MIPS32 = 4; - static constexpr const uint32_t MULTIBOOT_HEADER_TAG_OPTIONAL = 1; + static constexpr const uint32_t MULTIBOOT_ARCHITECTURE_I386 = 0; + static constexpr const uint32_t MULTIBOOT_ARCHITECTURE_MIPS32 = 4; + static constexpr const uint32_t MULTIBOOT_HEADER_TAG_OPTIONAL = 1; - static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_NONE = 0; - static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_LOW = 1; - static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_HIGH = 2; + static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_NONE = 0; + static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_LOW = 1; + static constexpr const uint32_t MULTIBOOT_LOAD_PREFERENCE_HIGH = 2; - static constexpr const uint32_t MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED = - 1; - static constexpr const uint32_t MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED = - 2; + static constexpr const uint32_t MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED + = 1; + static constexpr const uint32_t MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED + = 2; struct multiboot_header_t { // Must be MULTIBOOT_MAGIC - see above. @@ -172,6 +172,7 @@ class MULTIBOOT2 { static constexpr const uint32_t MULTIBOOT_MEMORY_ACPI_RECLAIMABLE = 3; static constexpr const uint32_t MULTIBOOT_MEMORY_NVS = 4; static constexpr const uint32_t MULTIBOOT_MEMORY_BADRAM = 5; + struct multiboot_mmap_entry_t { uint64_t addr; uint64_t len; @@ -220,10 +221,10 @@ class MULTIBOOT2 { }; struct multiboot_tag_vbe_t : multiboot_tag_t { - uint16_t vbe_mode; - uint16_t vbe_interface_seg; - uint16_t vbe_interface_off; - uint16_t vbe_interface_len; + uint16_t vbe_mode; + uint16_t vbe_interface_seg; + uint16_t vbe_interface_off; + uint16_t vbe_interface_len; multiboot_vbe_info_block_t vbe_control_info; multiboot_vbe_mode_info_block_t vbe_mode_info; @@ -306,22 +307,21 @@ class MULTIBOOT2 { * @brief 获取单例 * @return MULTIBOOT2& 静态对象 */ - static MULTIBOOT2 &get_instance(void); + static MULTIBOOT2& get_instance(void); /** * @brief 初始化 * @return true 成功 * @return false 失败 */ - bool multiboot2_init(void); + bool multiboot2_init(void); /** * @brief 迭代器 * @param _fun 迭代操作 * @param _data 数据 */ - void multiboot2_iter(bool (*_fun)(const iter_data_t *, void *), - void *_data); + void multiboot2_iter(bool (*_fun)(const iter_data_t*, void*), void* _data); /** * @brief 获取内存信息 @@ -330,12 +330,12 @@ class MULTIBOOT2 { * @return true 成功 * @return false 失败 */ - static bool get_memory(const iter_data_t *_iter_data, void *_data); + static bool get_memory(const iter_data_t* _iter_data, void* _data); }; namespace BOOT_INFO { /// 魔数 extern "C" uint32_t multiboot2_magic; -}; // namespace BOOT_INFO +}; // namespace BOOT_INFO -#endif /* _MULTIBOOT2_H_ */ +#endif /* SIMPLEKERNEL_MULTIBOOT2_H */ diff --git a/src/drv/multiboot2/multiboot2.cpp b/src/drv/multiboot2/multiboot2.cpp index d4f603b0a..463a3dedb 100644 --- a/src/drv/multiboot2/multiboot2.cpp +++ b/src/drv/multiboot2/multiboot2.cpp @@ -14,14 +14,14 @@ * */ -#include "assert.h" -#include "stdio.h" -#include "common.h" #include "multiboot2.h" #include "boot_info.h" +#include "cassert" +#include "common.h" +#include "cstdio" #include "resource.h" -MULTIBOOT2 &MULTIBOOT2::get_instance(void) { +MULTIBOOT2& MULTIBOOT2::get_instance(void) { /// 定义全局 MULTIBOOT2 对象 static MULTIBOOT2 multiboot2; return multiboot2; @@ -33,18 +33,18 @@ bool MULTIBOOT2::multiboot2_init(void) { assert(BOOT_INFO::multiboot2_magic == MULTIBOOT2_BOOTLOADER_MAGIC); assert((reinterpret_cast(addr) & 7) == 0); // addr+0 保存大小 - BOOT_INFO::boot_info_size = *(uint32_t *)addr; + BOOT_INFO::boot_info_size = *(uint32_t*)addr; return true; } /// @todo 优化 -void MULTIBOOT2::multiboot2_iter(bool (*_fun)(const iter_data_t *, void *), - void *_data) { - uintptr_t addr = BOOT_INFO::boot_info_addr; +void MULTIBOOT2::multiboot2_iter(bool (*_fun)(const iter_data_t*, void*), + void* _data) { + uintptr_t addr = BOOT_INFO::boot_info_addr; // 下一字节开始为 tag 信息 - iter_data_t *tag = (iter_data_t *)(addr + 8); + iter_data_t* tag = (iter_data_t*)(addr + 8); for (; tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (iter_data_t *)((uint8_t *)tag + COMMON::ALIGN(tag->size, 8))) { + tag = (iter_data_t*)((uint8_t*)tag + COMMON::ALIGN(tag->size, 8))) { if (_fun(tag, _data) == true) { return; } @@ -61,26 +61,28 @@ void MULTIBOOT2::multiboot2_iter(bool (*_fun)(const iter_data_t *, void *), // 0x100000(0x7EF0000) 0x1 // 0x7FF0000(0x10000) 0x3 // 0xFFFC0000(0x40000) 0x2 -bool MULTIBOOT2::get_memory(const iter_data_t *_iter_data, void *_data) { +bool MULTIBOOT2::get_memory(const iter_data_t* _iter_data, void* _data) { if (_iter_data->type != MULTIBOOT2::MULTIBOOT_TAG_TYPE_MMAP) { return false; } - resource_t *resource = (resource_t *)_data; - resource->type |= resource_t::MEM; - resource->name = (char *)"available phy memory"; - resource->mem.addr = 0x0; - resource->mem.len = 0; - MULTIBOOT2::multiboot_mmap_entry_t *mmap = - ((MULTIBOOT2::multiboot_tag_mmap_t *)_iter_data)->entries; - for (; (uint8_t *)mmap < (uint8_t *)_iter_data + _iter_data->size; - mmap = (MULTIBOOT2::multiboot_mmap_entry_t - *)((uint8_t *)mmap + - ((MULTIBOOT2::multiboot_tag_mmap_t *)_iter_data) - ->entry_size)) { + resource_t* resource = (resource_t*)_data; + resource->type |= resource_t::MEM; + resource->name = (char*)"available phy memory"; + resource->mem.addr = 0x0; + resource->mem.len = 0; + MULTIBOOT2::multiboot_mmap_entry_t* mmap + = ((MULTIBOOT2::multiboot_tag_mmap_t*)_iter_data)->entries; + for (; (uint8_t*)mmap < (uint8_t*)_iter_data + _iter_data->size; + mmap + = (MULTIBOOT2:: + multiboot_mmap_entry_t*)((uint8_t*)mmap + + ((MULTIBOOT2::multiboot_tag_mmap_t*) + _iter_data) + ->entry_size)) { // 如果是可用内存或地址小于 1M // 这里将 0~1M 的空间全部算为可用,在 c++ 库可用后进行优化 - if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE || - mmap->addr < 1 * COMMON::MB) { + if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE + || mmap->addr < 1 * COMMON::MB) { // 长度+ resource->mem.len += mmap->len; } @@ -92,13 +94,13 @@ namespace BOOT_INFO { // 地址 uintptr_t boot_info_addr; // 长度 -size_t boot_info_size; +size_t boot_info_size; // 魔数 -uint32_t multiboot2_magic; +uint32_t multiboot2_magic; -bool inited = false; +bool inited = false; -bool init(void) { +bool init(void) { auto res = MULTIBOOT2::get_instance().multiboot2_init(); if (inited == false) { inited = true; @@ -116,4 +118,4 @@ resource_t get_memory(void) { &resource); return resource; } -}; // namespace BOOT_INFO +}; // namespace BOOT_INFO diff --git a/src/drv/opensbi/include/opensbi.h b/src/drv/opensbi/include/opensbi.h index b2d449145..c02b641a1 100644 --- a/src/drv/opensbi/include/opensbi.h +++ b/src/drv/opensbi/include/opensbi.h @@ -14,10 +14,10 @@ * */ -#ifndef _OPENSBI_H_ -#define _OPENSBI_H_ +#ifndef SIMPLEKERNEL_OPENSBI_H +#define SIMPLEKERNEL_OPENSBI_H -#include "stdint.h" +#include "cstdint" /** * @brief opensbi 接口抽象 @@ -41,6 +41,7 @@ class OPENSBI { ERR_ALREADY_STARTED = -7, ERR_ALREADY_STOPPED = -8, }; + /// 错误码 long error; /// 返回值 @@ -49,8 +50,8 @@ class OPENSBI { private: /// 设置定时器 - static constexpr const uint32_t FID_SET_TIMER = 0x0; - static constexpr const uint32_t EID_SET_TIMER = 0x54494D45; + static constexpr const uint32_t FID_SET_TIMER = 0x0; + static constexpr const uint32_t EID_SET_TIMER = 0x54494D45; /// uart 输出字符 static constexpr const uint32_t FID_CONSOLE_PUTCHAR = 0x0; @@ -61,20 +62,20 @@ class OPENSBI { static constexpr const uint32_t EID_CONSOLE_GETCHAR = 0x2; /// 清空 IPI - static constexpr const uint32_t FID_CLEAR_IPI = 0x0; - static constexpr const uint32_t EID_CLEAR_IPI = 0x3; + static constexpr const uint32_t FID_CLEAR_IPI = 0x0; + static constexpr const uint32_t EID_CLEAR_IPI = 0x3; /// 发送 IPI - static constexpr const uint32_t FID_SEND_IPI = 0x0; - static constexpr const uint32_t EID_SEND_IPI = 0x735049; + static constexpr const uint32_t FID_SEND_IPI = 0x0; + static constexpr const uint32_t EID_SEND_IPI = 0x735049; /// 关机 - static constexpr const uint32_t FID_SHUTDOWN = 0x0; - static constexpr const uint32_t EID_SHUTDOWN = 0x8; + static constexpr const uint32_t FID_SHUTDOWN = 0x0; + static constexpr const uint32_t EID_SHUTDOWN = 0x8; /// 启动 hart - static constexpr const uint32_t FID_HART_START = 0x0; - static constexpr const uint32_t EID_HART_START = 0x48534D; + static constexpr const uint32_t FID_HART_START = 0x0; + static constexpr const uint32_t EID_HART_START = 0x48534D; /** * @brief ecall 借口 @@ -88,38 +89,39 @@ class OPENSBI { * @param _eid 使用 a7 传递 * @return sbiret_t */ - sbiret_t ecall(unsigned long _arg0, unsigned long _arg1, - unsigned long _arg2, unsigned long _arg3, - unsigned long _arg4, unsigned long _arg5, int _fid, - int _eid); + sbiret_t + ecall(unsigned long _arg0, unsigned long _arg1, unsigned long _arg2, + unsigned long _arg3, unsigned long _arg4, unsigned long _arg5, + int _fid, int _eid); protected: + public: /** * @brief 获取单例 * @return OPENSBI& 静态对象 */ - static OPENSBI &get_instance(void); + static OPENSBI& get_instance(void); /** * @brief 输出一个字符 * @param _c 要输出的字符 */ - void put_char(const char _c); + void put_char(const char _c); /** * @brief 从 uart 读取一个字符 * @return uint8_t 读取到的字符,没有读到数据返回 0xFF * @note 不会阻塞 */ - uint8_t get_char(void); + uint8_t get_char(void); /** * @brief 设置时钟 * @param _value 要设置的时间 * @return sbiret_t 返回值 */ - sbiret_t set_timer(uint64_t _value); + sbiret_t set_timer(uint64_t _value); /** * @brief 发送 ipi(inter-processor interrupt) 给指定的 hart @@ -130,7 +132,7 @@ class OPENSBI { * number of bits in an unsigned long, rounded up to the next integer. * @return sbiret_t 返回值 */ - sbiret_t send_ipi(const unsigned long *_hart_mask); + sbiret_t send_ipi(const unsigned long* _hart_mask); /** * @brief 启动指定的 hart @@ -146,8 +148,8 @@ class OPENSBI { * a0: hartid * a1: _opaque */ - sbiret_t hart_start(unsigned long _hartid, unsigned long _start_addr, - unsigned long _opaque); + sbiret_t hart_start(unsigned long _hartid, unsigned long _start_addr, + unsigned long _opaque); }; -#endif /* _OPENSBI_H_ */ +#endif /* SIMPLEKERNEL_OPENSBI_H */ diff --git a/src/drv/opensbi/opensbi.cpp b/src/drv/opensbi/opensbi.cpp index 45565ec03..c544d469d 100644 --- a/src/drv/opensbi/opensbi.cpp +++ b/src/drv/opensbi/opensbi.cpp @@ -16,10 +16,10 @@ #include "opensbi.h" -OPENSBI::sbiret_t OPENSBI::ecall(unsigned long _arg0, unsigned long _arg1, - unsigned long _arg2, unsigned long _arg3, - unsigned long _arg4, unsigned long _arg5, - int _fid, int _eid) { +OPENSBI::sbiret_t +OPENSBI::ecall(unsigned long _arg0, unsigned long _arg1, unsigned long _arg2, + unsigned long _arg3, unsigned long _arg4, unsigned long _arg5, + int _fid, int _eid) { OPENSBI::sbiret_t ret; register uintptr_t a0 asm("a0") = (uintptr_t)(_arg0); register uintptr_t a1 asm("a1") = (uintptr_t)(_arg1); @@ -29,16 +29,16 @@ OPENSBI::sbiret_t OPENSBI::ecall(unsigned long _arg0, unsigned long _arg1, register uintptr_t a5 asm("a5") = (uintptr_t)(_arg5); register uintptr_t a6 asm("a6") = (uintptr_t)(_fid); register uintptr_t a7 asm("a7") = (uintptr_t)(_eid); - asm volatile("ecall" - : "+r"(a0), "+r"(a1) - : "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6), "r"(a7) - : "memory"); + asm("ecall" + : "+r"(a0), "+r"(a1) + : "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6), "r"(a7) + : "memory"); ret.error = a0; ret.value = a1; return ret; } -OPENSBI &OPENSBI::get_instance(void) { +OPENSBI& OPENSBI::get_instance(void) { /// 定义全局 OPENSBI 对象 static OPENSBI opensbi; return opensbi; @@ -52,21 +52,21 @@ void OPENSBI::put_char(const char _c) { uint8_t OPENSBI::get_char(void) { return (uint8_t)ecall(0, 0, 0, 0, 0, 0, FID_CONSOLE_GETCHAR, EID_CONSOLE_GETCHAR) - .value; + .value; } OPENSBI::sbiret_t OPENSBI::set_timer(uint64_t _value) { return ecall(_value, 0, 0, 0, 0, 0, FID_SET_TIMER, EID_SET_TIMER); } -OPENSBI::sbiret_t OPENSBI::send_ipi(const unsigned long *_hart_mask) { +OPENSBI::sbiret_t OPENSBI::send_ipi(const unsigned long* _hart_mask) { return ecall((uintptr_t)_hart_mask, 0, 0, 0, 0, 0, FID_SEND_IPI, EID_SEND_IPI); } -OPENSBI::sbiret_t OPENSBI::hart_start(unsigned long _hartid, - unsigned long _start_addr, - unsigned long _opaque) { +OPENSBI::sbiret_t +OPENSBI::hart_start(unsigned long _hartid, unsigned long _start_addr, + unsigned long _opaque) { return ecall(_hartid, _start_addr, _opaque, 0, 0, 0, FID_HART_START, EID_HART_START); } diff --git a/src/drv/sbi_console/include/sbi_console.h b/src/drv/sbi_console/include/sbi_console.h index fd588224d..b71dcb862 100644 --- a/src/drv/sbi_console/include/sbi_console.h +++ b/src/drv/sbi_console/include/sbi_console.h @@ -14,11 +14,12 @@ * */ -#ifndef _SBI_CONSOLE_H_ -#define _SBI_CONSOLE_H_ +#ifndef SIMPLEKERNEL_SBI_CONSOLE_H +#define SIMPLEKERNEL_SBI_CONSOLE_H -#include "stdint.h" #include "color.h" +#include "cstddef" +#include "cstdint" class SBI_CONSOLE { private: @@ -26,6 +27,7 @@ class SBI_CONSOLE { static COLOR::color_t color; protected: + public: SBI_CONSOLE(void); ~SBI_CONSOLE(void); @@ -34,34 +36,34 @@ class SBI_CONSOLE { * @brief 写字符 * @param _c 要写的字符 */ - void put_char(const char _c) const; + void put_char(const char _c) const; /** * @brief 写字符串 * @param _s 要写的字符串 */ - void write_string(const char *_s) const; + void write_string(const char* _s) const; /** * @brief 写指定长度的字符串 * @param _s 要写的字符串 * @param _len 要写的长度 */ - void write(const char *_s, size_t _len) const; + void write(const char* _s, size_t _len) const; /** * @brief 读一个字符 * @return uint8_t 读取到的字符 * @todo */ - uint8_t get_char(void) const; + uint8_t get_char(void) const; /** * @brief 设置颜色 * @param _color 要设置的颜色 * @todo */ - void set_color(const COLOR::color_t _color) const; + void set_color(const COLOR::color_t _color) const; /** * @brief 获取正在使用的颜色 @@ -71,4 +73,4 @@ class SBI_CONSOLE { COLOR::color_t get_color(void) const; }; -#endif /* _SBI_CONSOLE_H_ */ +#endif /* SIMPLEKERNEL_SBI_CONSOLE_H */ diff --git a/src/drv/sbi_console/sbi_console.cpp b/src/drv/sbi_console/sbi_console.cpp index 540da1292..20b1f7e5d 100644 --- a/src/drv/sbi_console/sbi_console.cpp +++ b/src/drv/sbi_console/sbi_console.cpp @@ -14,11 +14,9 @@ * */ -#include "stddef.h" -#include "string.h" -#include "stdlib.h" -#include "opensbi.h" #include "sbi_console.h" +#include "cstring" +#include "opensbi.h" // 默认颜色为白色 COLOR::color_t SBI_CONSOLE::color = COLOR::WHITE; @@ -39,12 +37,12 @@ void SBI_CONSOLE::put_char(const char _c) const { return; } -void SBI_CONSOLE::write_string(const char *_s) const { +void SBI_CONSOLE::write_string(const char* _s) const { write(_s, strlen(_s)); return; } -void SBI_CONSOLE::write(const char *_s, size_t _len) const { +void SBI_CONSOLE::write(const char* _s, size_t _len) const { for (size_t i = 0; i < _len; i++) { put_char(_s[i]); } @@ -57,70 +55,70 @@ uint8_t SBI_CONSOLE::get_char(void) const { void SBI_CONSOLE::set_color(const COLOR::color_t _color) const { // 根据 _color 构造字符串 - char *tmp = nullptr; + char* tmp = nullptr; switch (_color) { case COLOR::BLACK: { - tmp = (char *)"\033[30m"; + tmp = (char*)"\033[30m"; break; } case COLOR::RED: { - tmp = (char *)"\033[31m"; + tmp = (char*)"\033[31m"; break; } case COLOR::GREEN: { - tmp = (char *)"\033[32m"; + tmp = (char*)"\033[32m"; break; } case COLOR::YELLOW: { - tmp = (char *)"\033[33m"; + tmp = (char*)"\033[33m"; break; } case COLOR::BLUE: { - tmp = (char *)"\033[34m"; + tmp = (char*)"\033[34m"; break; } case COLOR::PURPLE: { - tmp = (char *)"\033[35m"; + tmp = (char*)"\033[35m"; break; } case COLOR::CYAN: { - tmp = (char *)"\033[36m"; + tmp = (char*)"\033[36m"; break; } case COLOR::WHITE: { - tmp = (char *)"\033[37m"; + tmp = (char*)"\033[37m"; break; } case COLOR::GREY: { - tmp = (char *)"\033[90m"; + tmp = (char*)"\033[90m"; break; } case COLOR::LIGHT_RED: { - tmp = (char *)"\033[91m"; + tmp = (char*)"\033[91m"; break; } case COLOR::LIGHT_GREEN: { - tmp = (char *)"\033[92m"; + tmp = (char*)"\033[92m"; break; } case COLOR::LIGHT_YELLOW: { - tmp = (char *)"\033[93m"; + tmp = (char*)"\033[93m"; break; } case COLOR::LIGHT_BLUE: { - tmp = (char *)"\033[94m"; + tmp = (char*)"\033[94m"; break; } case COLOR::LIGHT_PURPLE: { - tmp = (char *)"\033[95m"; + tmp = (char*)"\033[95m"; break; } case COLOR::LIGHT_CYAN: { - tmp = (char *)"\033[96m"; + tmp = (char*)"\033[96m"; break; } case COLOR::LIGHT_WHITE: { - tmp = (char *)"\033[97m"; + tmp = (char*)"\033[97m"; break; } } diff --git a/src/drv/tui/include/tui.h b/src/drv/tui/include/tui.h index bb7a6a6dc..435964d9b 100644 --- a/src/drv/tui/include/tui.h +++ b/src/drv/tui/include/tui.h @@ -1,6 +1,6 @@ /** - * @file tui.cpp + * @file tui.h * @brief TUI 接口头文件 * @author Zone.N (Zone.Niuzh@hotmail.com) * @version 1.0 @@ -14,12 +14,12 @@ * */ -#ifndef _TUI_H_ -#define _TUI_H_ +#ifndef SIMPLEKERNEL_TUI_H +#define SIMPLEKERNEL_TUI_H -#include "stdint.h" -#include "stddef.h" #include "color.h" +#include "cstddef" +#include "cstdint" /** * @brief 位置信息 @@ -77,7 +77,7 @@ class char_t { // 字符 uint8_t c; // 颜色 - col_t color; + col_t color; }; /** @@ -86,9 +86,9 @@ class char_t { class TUI { private: /// CRT 控制寄存器-地址 - static constexpr const uint32_t TUI_ADDR = 0x3D4; + static constexpr const uint32_t TUI_ADDR = 0x3D4; /// CRT 控制寄存器-数据 - static constexpr const uint32_t TUI_DATA = 0x3D5; + static constexpr const uint32_t TUI_DATA = 0x3D5; /// 光标高位 static constexpr const uint32_t TUI_CURSOR_H = 0xE; /// 光标低位 @@ -98,19 +98,19 @@ class TUI { static constexpr const uint32_t TUI_MEM_BASE = 0xB8000; /// TUI 缓存大小 /// @todo 从 grub 获取 - static constexpr size_t TUI_MEM_SIZE = 0x8000; + static constexpr size_t TUI_MEM_SIZE = 0x8000; /// 规定显示行数 /// @todo 从 grub 获取 - static constexpr const size_t WIDTH = 80; + static constexpr const size_t WIDTH = 80; /// 规定显示列数 /// @todo 从 grub 获取 - static constexpr const size_t HEIGHT = 25; + static constexpr const size_t HEIGHT = 25; // TUI 缓存 - char_t *const buffer = (char_t *)TUI_MEM_BASE; + char_t* const buffer = (char_t*)TUI_MEM_BASE; /// 记录当前位置 - static pos_t pos; + static pos_t pos; /// 记录当前命令行颜色 - static col_t color; + static col_t color; /** * @brief 在指定位置输出 @@ -136,6 +136,7 @@ class TUI { void scroll(void); protected: + public: TUI(void); ~TUI(void); @@ -145,7 +146,7 @@ class TUI { * @param _color 要设置的颜色 * @todo 支持分别字体与背景色 */ - void set_color(const COLOR::color_t _color); + void set_color(const COLOR::color_t _color); /** * @brief 获取颜色 @@ -157,70 +158,70 @@ class TUI { * @brief 设置光标位置 * @param _pos 要设置的位置 */ - void set_pos(const pos_t _pos); + void set_pos(const pos_t _pos); /** * @brief 设置行 * @param _row 要设置的行 */ - void set_pos_row(const size_t _row); + void set_pos_row(const size_t _row); /** * @brief 设置列 * @param _col 要设置的列 */ - void set_pos_col(const size_t _col); + void set_pos_col(const size_t _col); /** * @brief 获取光标位置 * @return pos_t 光标的位置 */ - pos_t get_pos(void) const; + pos_t get_pos(void) const; /** * @brief 写 TUI 缓存 * @param _idx 要写的位置 * @param _data 要写的数据 */ - void write(const size_t _idx, const char_t _data); + void write(const size_t _idx, const char_t _data); /** * @brief 读 TUI 缓存 * @param _idx 要读的位置 * @return char_t 该位置处的 char_t 对象 */ - char_t read(const size_t _idx) const; + char_t read(const size_t _idx) const; /** * @brief 写字符 * @param _c 要写的字符 */ - void put_char(const char _c); + void put_char(const char _c); /** * @brief 读字符 * @return uint8_t 读到的字符 * @note tui 没有读字符的操作,这里只是保持接口一致 */ - uint8_t get_char(void) const; + uint8_t get_char(void) const; /** * @brief 写字符串 * @param _s 要写的字符串 */ - void write_string(const char *_s); + void write_string(const char* _s); /** * @brief 写指定长度的字符串 * @param _s 要写的字符串 * @param _len 要写的长度 */ - void write(const char *_s, const size_t _len); + void write(const char* _s, const size_t _len); /** * @brief 清屏,清空 TUI 缓存 */ - void clear(void); + void clear(void); }; -#endif /* _TUI_H_ */ +#endif /* SIMPLEKERNEL_TUI_H */ diff --git a/src/drv/tui/tui.cpp b/src/drv/tui/tui.cpp index a2b64cb4c..a927215ac 100644 --- a/src/drv/tui/tui.cpp +++ b/src/drv/tui/tui.cpp @@ -14,11 +14,10 @@ * */ -#include "stddef.h" -#include "stdint.h" -#include "stdarg.h" -#include "string.h" #include "tui.h" +#include "cstddef" +#include "cstdint" +#include "cstring" #include "port.h" pos_t::pos_t(const uint8_t _col, const uint8_t _row) : col(_col), row(_row) { @@ -193,12 +192,12 @@ uint8_t TUI::get_char(void) const { return 0; } -void TUI::write_string(const char *_s) { +void TUI::write_string(const char* _s) { write(_s, strlen(_s)); return; } -void TUI::write(const char *_s, const size_t _len) { +void TUI::write(const char* _s, const size_t _len) { for (size_t i = 0; i < _len; i++) { put_char(_s[i]); } diff --git a/src/drv/uart/include/uart.h b/src/drv/uart/include/uart.h index 9bea5e5a7..1467950f6 100644 --- a/src/drv/uart/include/uart.h +++ b/src/drv/uart/include/uart.h @@ -1,15 +1,25 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// uart.h for Simple-XX/SimpleKernel. +/** + * @file uart.h + * @brief uart 驱动 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _UART_H_ -#define _UART_H_ +#ifndef SIMPLEKERNEL_UART_H +#define SIMPLEKERNEL_UART_H -#include "stddef.h" -#include "stdint.h" #include "color.h" +#include "cstddef" +#include "cstdint" #include "hardware.h" class UART { @@ -38,20 +48,21 @@ class UART { void delay(int32_t count) const; protected: + public: UART(void); ~UART(void); - void put_char(const char _c) const; + void put_char(const char _c) const; // 写字符串 - void write_string(const char *_s) const; + void write_string(const char* _s) const; // 写字符串 - void write(const char *_s, size_t _len) const; + void write(const char* _s, size_t _len) const; // 读字符 TODO - uint8_t get_char(void) const; + uint8_t get_char(void) const; // 设置颜色 TODO - void set_color(const COLOR::color_t _color) const; + void set_color(const COLOR::color_t _color) const; // 获取颜色 TODO COLOR::color_t get_color(void) const; }; -#endif /* _UART_H_ */ +#endif /* SIMPLEKERNEL_UART_H */ diff --git a/src/drv/uart/uart.cpp b/src/drv/uart/uart.cpp index adb74cf04..20c40e186 100644 --- a/src/drv/uart/uart.cpp +++ b/src/drv/uart/uart.cpp @@ -1,12 +1,23 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://wiki.osdev.org/Raspberry_Pi_Bare_Bones -// uart.cpp for Simple-XX/SimpleKernel. +/** + * @file uart.cpp + * @brief uart 驱动实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://wiki.osdev.org/Raspberry_Pi_Bare_Bones + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#include "stddef.h" -#include "string.h" #include "uart.h" +#include "cstddef" +#include "cstring" #include "port.h" UART::UART(void) { @@ -41,8 +52,8 @@ UART::UART(void) { PORT::outd(UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); // Mask all interrupts. - PORT::outd(UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | - (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)); + PORT::outd(UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) + | (1 << 8) | (1 << 9) | (1 << 10)); // Enable UART0, receive & transfer part of UART. PORT::outd(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); @@ -71,12 +82,12 @@ void UART::put_char(const char _c) const { return; } -void UART::write_string(const char *_s) const { +void UART::write_string(const char* _s) const { write(_s, strlen(_s)); return; } -void UART::write(const char *_s, size_t _len) const { +void UART::write(const char* _s, size_t _len) const { for (size_t i = 0; i < _len; i++) { put_char(_s[i]); } diff --git a/src/include/boot_info.h b/src/include/boot_info.h index a0c39330b..b9e7d497f 100644 --- a/src/include/boot_info.h +++ b/src/include/boot_info.h @@ -14,10 +14,10 @@ * */ -#ifndef _BOOT_INFO_H_ -#define _BOOT_INFO_H_ +#ifndef SIMPLEKERNEL_BOOT_INFO_H +#define SIMPLEKERNEL_BOOT_INFO_H -#include "stdint.h" +#include "cstdint" #include "resource.h" /** @@ -32,36 +32,38 @@ namespace BOOT_INFO { /// 声明,定义在具体的实现中 /// 是否已经初始化过 -extern bool inited; +extern bool inited; /// 地址 extern "C" uintptr_t boot_info_addr; /// 长度 -extern size_t boot_info_size; +extern size_t boot_info_size; +/// 保存 sbi 传递的启动核 +extern "C" size_t dtb_init_hart; /** * @brief 初始化,定义在具体实现中 * @return true 成功 * @return false 成功 */ -extern bool init(void); +extern bool init(void); /** * @brief 获取物理内存信息 * @return resource_t 物理内存资源信息 */ -extern resource_t get_memory(void); +extern resource_t get_memory(void); /** * @brief 获取 clint 信息 * @return resource_t clint 资源信息 */ -extern resource_t get_clint(void); +extern resource_t get_clint(void); /** * @brief 获取 plic 信息 * @return resource_t plic 资源信息 */ -extern resource_t get_plic(void); -}; // namespace BOOT_INFO +extern resource_t get_plic(void); +}; // namespace BOOT_INFO -#endif /* _BOOT_INFO_H_ */ +#endif /* SIMPLEKERNEL_BOOT_INFO_H */ diff --git a/src/include/color.h b/src/include/color.h index 2ace8ce79..252323782 100644 --- a/src/include/color.h +++ b/src/include/color.h @@ -14,10 +14,10 @@ * */ -#ifndef _COLOR_H_ -#define _COLOR_H_ +#ifndef SIMPLEKERNEL_COLOR_H +#define SIMPLEKERNEL_COLOR_H -#include "stdint.h" +#include "cstdint" /** * @brief 颜色定义 @@ -25,60 +25,60 @@ * @todo 标准化 */ namespace COLOR { - typedef enum : uint8_t { +typedef enum : uint8_t { #if defined(__i386__) || defined(__x86_64__) - /// RGB: 0 0 0 - BLACK = 0, - /// RGB: 0 0 170 - BLUE = 1, - /// RGB: 0 170 0 - GREEN = 2, - /// RGB: 0 170 170 - CYAN = 3, - /// RGB: 170 0 0 - RED = 4, - /// RGB: 170 0 170 - PURPLE = 5, - /// RGB: 170 85 0 - BROWN = 6, - /// RGB: 170 170 170 - GREY = 7, - /// RGB: 85 85 85 - DARK_GREY = 8, - /// RGB: 85 85 255 - LIGHT_BLUE = 9, - /// RGB: 85 255 85 - LIGHT_GREEN = 10, - /// RGB: 85 255 255 - LIGHT_CYAN = 11, - /// RGB: 255 85 85 - LIGHT_RED = 12, - /// RGB: 255 85 255 - LIGHT_PURPLE = 13, - /// RGB: 255 255 85 - YELLOW = 14, - /// RGB: 255 255 255 - WHITE = 15, + /// RGB: 0 0 0 + BLACK = 0, + /// RGB: 0 0 170 + BLUE = 1, + /// RGB: 0 170 0 + GREEN = 2, + /// RGB: 0 170 170 + CYAN = 3, + /// RGB: 170 0 0 + RED = 4, + /// RGB: 170 0 170 + PURPLE = 5, + /// RGB: 170 85 0 + BROWN = 6, + /// RGB: 170 170 170 + GREY = 7, + /// RGB: 85 85 85 + DARK_GREY = 8, + /// RGB: 85 85 255 + LIGHT_BLUE = 9, + /// RGB: 85 255 85 + LIGHT_GREEN = 10, + /// RGB: 85 255 255 + LIGHT_CYAN = 11, + /// RGB: 255 85 85 + LIGHT_RED = 12, + /// RGB: 255 85 255 + LIGHT_PURPLE = 13, + /// RGB: 255 255 85 + YELLOW = 14, + /// RGB: 255 255 255 + WHITE = 15, #elif defined(__riscv) - /// @see https://en.wikipedia.org/wiki/ANSI_escape_code - BLACK = 30, - RED = 31, - GREEN = 32, - YELLOW = 33, - BLUE = 34, - PURPLE = 35, - CYAN = 36, - WHITE = 37, - GREY = 90, - LIGHT_RED = 91, - LIGHT_GREEN = 92, - LIGHT_YELLOW = 93, - LIGHT_BLUE = 94, - LIGHT_PURPLE = 95, - LIGHT_CYAN = 96, - LIGHT_WHITE = 97, + /// @see https://en.wikipedia.org/wiki/ANSI_escape_code + BLACK = 30, + RED = 31, + GREEN = 32, + YELLOW = 33, + BLUE = 34, + PURPLE = 35, + CYAN = 36, + WHITE = 37, + GREY = 90, + LIGHT_RED = 91, + LIGHT_GREEN = 92, + LIGHT_YELLOW = 93, + LIGHT_BLUE = 94, + LIGHT_PURPLE = 95, + LIGHT_CYAN = 96, + LIGHT_WHITE = 97, #endif - } color_t; -}; +} color_t; +}; // namespace COLOR -#endif /* _COLOR_H_ */ +#endif /* SIMPLEKERNEL_COLOR_H */ diff --git a/src/include/common.h b/src/include/common.h index 078e447ea..17c96190e 100644 --- a/src/include/common.h +++ b/src/include/common.h @@ -14,99 +14,82 @@ * */ -#ifndef _COMMON_H_ -#define _COMMON_H_ +#ifndef SIMPLEKERNEL_COMMON_H +#define SIMPLEKERNEL_COMMON_H -#include "stdint.h" -#include "stddef.h" +#include "cstddef" +#include "cstdint" namespace COMMON { - // 引用链接脚本中的变量 - /// @see http://wiki.osdev.org/Using_Linker_Script_Values - /// 内核开始 - extern "C" void *kernel_start[]; - /// 内核代码段开始 - extern "C" void *kernel_text_start[]; - /// 内核代码段结束 - extern "C" void *kernel_text_end[]; - /// 内核数据段开始 - extern "C" void *kernel_data_start[]; - /// 内核数据段结束 - extern "C" void *kernel_data_end[]; - /// 内核结束 - extern "C" void *kernel_end[]; +// 引用链接脚本中的变量 +/// @see http://wiki.osdev.org/Using_Linker_Script_Values +/// 内核开始 +extern "C" void* __executable_start[]; +/// 内核结束 +extern "C" void* end[]; - /// 内核开始 - static const uintptr_t KERNEL_START_ADDR = - reinterpret_cast(kernel_start); - /// 内核代码段开始 - static const uintptr_t KERNEL_TEXT_START_ADDR __attribute__((unused)) = - reinterpret_cast(kernel_text_start); - /// 内核代码段结束 - static const uintptr_t KERNEL_TEXT_END_ADDR __attribute__((unused)) = - reinterpret_cast(kernel_text_end); - /// 内核数据段开始 - static const uintptr_t KERNEL_DATA_START_ADDR __attribute__((unused)) = - reinterpret_cast(kernel_data_start); - /// 内核数据段结束 - static const uintptr_t KERNEL_DATA_END_ADDR __attribute__((unused)) = - reinterpret_cast(kernel_data_end); - /// 内核结束 - static const uintptr_t KERNEL_END_ADDR = - reinterpret_cast(kernel_end); +/// 内核开始 +static const uintptr_t KERNEL_START_ADDR + = reinterpret_cast(__executable_start); +/// 内核结束 +static const uintptr_t KERNEL_END_ADDR = reinterpret_cast(end); - // 规定数据大小,方便用 - /// 一个字节,8 bits - static constexpr const size_t BYTE = 0x1; - /// 1KB - static constexpr const size_t KB = 0x400; - /// 1MB - static constexpr const size_t MB = 0x100000; - /// 1GB - static constexpr const size_t GB = 0x40000000; - /// 页大小 4KB - static constexpr const size_t PAGE_SIZE = 4 * KB; - /// 内核空间占用大小,包括内核代码部分与预留的,8MB - static constexpr const uint32_t KERNEL_SPACE_SIZE = 8 * MB; - /// 映射内核空间需要的页数 - static constexpr const uint64_t KERNEL_SPACE_PAGES = - KERNEL_SPACE_SIZE / PAGE_SIZE; +// 规定数据大小,方便用 +/// 一个字节,8 bits +static constexpr const size_t BYTE = 0x1; +/// 1KB +static constexpr const size_t KB = 0x400; +/// 1MB +static constexpr const size_t MB = 0x100000; +/// 1GB +static constexpr const size_t GB = 0x40000000; +/// 页大小 4KB +static constexpr const size_t PAGE_SIZE = 4 * KB; +/// 内核空间占用大小,包括内核代码部分与预留的,8MB +static constexpr const uint32_t KERNEL_SPACE_SIZE = 8 * MB; +/// 映射内核空间需要的页数 +static constexpr const uint64_t KERNEL_SPACE_PAGES + = KERNEL_SPACE_SIZE / PAGE_SIZE; +/// 栈大小 +static constexpr const uintptr_t STACK_SIZE = 4 * KB; - // 页掩码 - static constexpr const uintptr_t PAGE_MASK = ~(PAGE_SIZE - 1); +// 页掩码 +static constexpr const uintptr_t PAGE_MASK = ~(PAGE_SIZE - 1); - /** - * @brief 对齐 - * @tparam T - * @param _addr 要对齐的地址 - * @param _align 要对齐的目标 - * @return T 对齐过的地址 - * @note 向上取整 - * @note 针对指针 - */ - template - inline T ALIGN(const T _addr, size_t _align) { - uint8_t *tmp = (uint8_t *)_addr; - return (T)((uintptr_t)(tmp + _align - 1) & (~(_align - 1))); - } +/** + * @brief 对齐 + * @tparam T + * @param _addr 要对齐的地址 + * @param _align 要对齐的目标 + * @return T 对齐过的地址 + * @note 向上取整 + * @note 针对指针 + */ +template +inline T ALIGN(const T _addr, const size_t _align) { + uint8_t* tmp = reinterpret_cast(_addr); + return (T)((ptrdiff_t)(tmp + _align - 1) & (~(_align - 1))); +} + +/** + * @brief 对齐 + * @tparam T + * @param _addr 要对齐的整数 + * @param _align 要对齐的目标 + * @return T 对齐过的整数 + * @note 向上取整 + * @note 针对整数 + */ +template <> +inline uint32_t ALIGN(uint32_t _x, size_t _align) { + return ((_x + _align - 1) & (~(_align - 1))); +} + +template <> +inline uint64_t ALIGN(uint64_t _x, size_t _align) { + return ((_x + _align - 1) & (~(_align - 1))); +} - /** - * @brief 对齐 - * @tparam T - * @param _addr 要对齐的整数 - * @param _align 要对齐的目标 - * @return T 对齐过的整数 - * @note 向上取整 - * @note 针对整数 - */ - template <> - inline uint32_t ALIGN(uint32_t _x, size_t _align) { - return ((_x + _align - 1) & (~(_align - 1))); - } - template <> - inline uint64_t ALIGN(uint64_t _x, size_t _align) { - return ((_x + _align - 1) & (~(_align - 1))); - } -}; +}; // namespace COMMON -#endif /* _COMMON_H_ */ +#endif /* SIMPLEKERNEL_COMMON_H */ diff --git a/src/include/io.h b/src/include/io.h index 2f5ef456a..b29cc1f14 100644 --- a/src/include/io.h +++ b/src/include/io.h @@ -14,19 +14,19 @@ * */ -#ifndef _IO_H_ -#define _IO_H_ +#ifndef SIMPLEKERNEL_IO_H +#define SIMPLEKERNEL_IO_H -#include "stdint.h" #include "color.h" +#include "cstdint" // 根据不同架构选择不同的输出方式 #if defined(__i386__) || defined(__x86_64__) -#include "tui.h" +# include "tui.h" #elif defined(__arm__) || defined(__aarch64__) -#include "uart.h" +# include "uart.h" #elif defined(__riscv) -#include "sbi_console.h" +# include "sbi_console.h" #endif /** @@ -47,138 +47,139 @@ class IO { #endif protected: + public: /// 缓冲区大小 - static constexpr const size_t BUF_SIZE = 128; + static constexpr const size_t BUF_SIZE = 512; /** * @brief 获取单例 * @return IO& 静态对象 */ - static IO &get_instance(void); + static IO& get_instance(void); /** * @brief 端口读字节 * @param _port 要读的端口 * @return uint8_t 读到的数据 */ - uint8_t inb(const uint32_t _port); + static uint8_t inb(const uint32_t _port); /** * @brief 端口读字 * @param _port 要读的端口 * @return uint16_t 读到的数据 */ - uint16_t inw(const uint32_t _port); + static uint16_t inw(const uint32_t _port); /** * @brief 端口读双字 * @param _port 要读的端口 * @return uint32_t 读到的数据 */ - uint32_t ind(const uint32_t _port); + static uint32_t ind(const uint32_t _port); /** * @brief 端口写字节 * @param _port 要写的端口 * @param _data 要写的数据 */ - void outb(const uint32_t _port, const uint8_t _data); + static void outb(const uint32_t _port, const uint8_t _data); /** * @brief 端口写字 * @param _port 要写的端口 * @param _data 要写的数据 */ - void outw(const uint32_t _port, const uint16_t _data); + static void outw(const uint32_t _port, const uint16_t _data); /** * @brief 端口写双字 * @param _port 要写的端口 * @param _data 要写的数据 */ - void outd(const uint32_t _port, const uint32_t _data); + static void outd(const uint32_t _port, const uint32_t _data); /** * @brief MMIO 读字节 * @param _addr 要读的地址 * @return uint8_t 读到的数据 */ - uint8_t read8(void *_addr); + static uint8_t read8(void* _addr); /** * @brief MMIO 写字节 * @param _addr 要写的地址 * @param _val 要写的值 */ - void write8(void *_addr, uint8_t _val); + static void write8(void* _addr, uint8_t _val); /** * @brief MMIO 读字 * @param _addr 要读的地址 * @return uint16_t 读到的数据 */ - uint16_t read16(void *_addr); + static uint16_t read16(void* _addr); /** * @brief MMIO 写字 * @param _addr 要写的地址 * @param _val 要写的值 */ - void write16(void *_addr, uint16_t _val); + static void write16(void* _addr, uint16_t _val); /** * @brief MMIO 读双字 * @param _addr 要读的地址 * @return uint32_t 读到的数据 */ - uint32_t read32(void *_addr); + static uint32_t read32(void* _addr); /** * @brief MMIO 写双字 * @param _addr 要写的地址 * @param _val 要写的数据 */ - void write32(void *_addr, uint32_t _val); + static void write32(void* _addr, uint32_t _val); /** * @brief MMIO 读四字 * @param _addr 要读的地址 * @return uint64_t 读到的数据 */ - uint64_t read64(void *_addr); + static uint64_t read64(void* _addr); /** * @brief MMIO 写四字 * @param _addr 要写的地址 * @param _val 要写的数据 */ - void write64(void *_addr, uint64_t _val); + static void write64(void* _addr, uint64_t _val); /** * @brief 获取当前颜色 * @return COLOR::color_t 当前使用的颜色 */ - COLOR::color_t get_color(void); + COLOR::color_t get_color(void); /** * @brief 设置当前颜色 * @param _color 要设置的颜色 */ - void set_color(const COLOR::color_t _color); + void set_color(const COLOR::color_t _color); /** * @brief 输出字符 * @param _c 要输出的字符 */ - void put_char(const char _c); + void put_char(const char _c); /** * @brief 输入字符 * @return char 读到的字符 * @todo */ - char get_char(void); + char get_char(void); /** * @brief 输出字符串 @@ -186,7 +187,7 @@ class IO { * @return int32_t 输出的长度 * @todo 返回值 */ - int32_t write_string(const char *_s); + int32_t write_string(const char* _s); }; -#endif /* _IO_H_ */ +#endif /* SIMPLEKERNEL_IO_H */ diff --git a/src/include/mem/allocator.h b/src/include/mem/allocator.h index c25cc4512..9fa7f2a3e 100644 --- a/src/include/mem/allocator.h +++ b/src/include/mem/allocator.h @@ -14,28 +14,29 @@ * */ -#ifndef _ALLOCATOR_H_ -#define _ALLOCATOR_H_ +#ifndef SIMPLEKERNEL_ALLOCATOR_H +#define SIMPLEKERNEL_ALLOCATOR_H -#include "stddef.h" -#include "stdint.h" +#include "cstddef" +#include "cstdint" /** * @brief 内存分配器抽象类 */ class ALLOCATOR { private: + protected: /// 分配器名称 - const char *name; + const char* name; /// 当前管理的内存区域地址 - uintptr_t allocator_start_addr; + uintptr_t allocator_start_addr; /// 当前管理的内存区域长度 - size_t allocator_length; + size_t allocator_length; /// 当前管理的内存区域空闲长度 - size_t allocator_free_count; + size_t allocator_free_count; /// 当前管理的内存区域已使用长度 - size_t allocator_used_count; + size_t allocator_used_count; public: /** @@ -44,16 +45,16 @@ class ALLOCATOR { * @param _addr 要管理的内存开始地址 * @param _len 要管理的内存长度,单位以具体实现为准 */ - ALLOCATOR(const char *_name, uintptr_t _addr, size_t _len); + ALLOCATOR(const char* _name, uintptr_t _addr, size_t _len); - virtual ~ALLOCATOR(void) = 0; + virtual ~ALLOCATOR(void) = 0; /** * @brief 分配 _len 页 * @param _len 页数 * @return uintptr_t 分配到的地址 */ - virtual uintptr_t alloc(size_t _len) = 0; + virtual uintptr_t alloc(size_t _len) = 0; /** * @brief 在指定地址分配 _len 长度 @@ -62,26 +63,26 @@ class ALLOCATOR { * @return true 成功 * @return false 失败 */ - virtual bool alloc(uintptr_t _addr, size_t _len) = 0; + virtual bool alloc(uintptr_t _addr, size_t _len) = 0; /** * @brief 释放 _len 长度 * @param _addr 地址 * @param _len 长度 */ - virtual void free(uintptr_t _addr, size_t _len) = 0; + virtual void free(uintptr_t _addr, size_t _len) = 0; /** * @brief 已使用数量 * @return size_t 数量 */ - virtual size_t get_used_count(void) const = 0; + virtual size_t get_used_count(void) const = 0; /** * @brief 空闲数量 * @return size_t 数量 */ - virtual size_t get_free_count(void) const = 0; + virtual size_t get_free_count(void) const = 0; }; -#endif /* _ALLOCATOR_H_ */ +#endif /* SIMPLEKERNEL_ALLOCATOR_H */ diff --git a/src/include/mem/firstfit.h b/src/include/mem/firstfit.h index cccc1b56e..5df8a17ed 100644 --- a/src/include/mem/firstfit.h +++ b/src/include/mem/firstfit.h @@ -14,13 +14,13 @@ * */ -#ifndef _FIRTSTFIT_H_ -#define _FIRTSTFIT_H_ +#ifndef SIMPLEKERNEL_FIRTSTFIT_H +#define SIMPLEKERNEL_FIRTSTFIT_H -#include "stdint.h" -#include "stddef.h" -#include "common.h" #include "allocator.h" +#include "common.h" +#include "cstddef" +#include "cstdint" /** * @brief 使用 first fit 算法的分配器 @@ -31,19 +31,19 @@ class FIRSTFIT : ALLOCATOR { static constexpr const uint64_t BITS_PER_WORD = sizeof(uintptr_t); #if __WORDSIZE == 64 /// 字长为 64 时的 掩码 - static constexpr const uint64_t MASK = 0x3F; + static constexpr const uint64_t MASK = 0x3F; /// 2^6==64 static constexpr const uint64_t SHIFT = 6; #elif __WORDSIZE == 32 /// 字长为 32 时的 掩码 - static constexpr const uint64_t MASK = 0x1F; + static constexpr const uint64_t MASK = 0x1F; /// 2^5==32 static constexpr const uint64_t SHIFT = 5; #endif /// 位图数组长度,设置为占用一个页,4kb,32768 个位,每个 bit /// 代表一页,最大表示 128MB - static constexpr const size_t BITS_ARR_SIZE = - COMMON::PAGE_SIZE / BITS_PER_WORD; + static constexpr const size_t BITS_ARR_SIZE + = COMMON::PAGE_SIZE / BITS_PER_WORD; /// 位图,每一位表示一页内存,1 表示已使用,0 表示未使用 uintptr_t map[BITS_ARR_SIZE]; @@ -51,13 +51,13 @@ class FIRSTFIT : ALLOCATOR { * @brief 置位 _idx * @param _idx 要置位的索引 */ - void set(size_t _idx); + void set(size_t _idx); /** * @brief 清零 _idx * @param _idx 要清零的索引 */ - void clr(size_t _idx); + void clr(size_t _idx); /** * @brief 测试 _idx @@ -65,7 +65,7 @@ class FIRSTFIT : ALLOCATOR { * @return true 已使用 * @return false 未使用 */ - bool test(size_t _idx) const; + bool test(size_t _idx) const; /** * @brief 寻找连续 _len 个 _val 位,返回开始索引 @@ -73,9 +73,10 @@ class FIRSTFIT : ALLOCATOR { * @param _val 值 * @return size_t 开始索引 */ - size_t find_len(size_t _len, bool _val) const; + size_t find_len(size_t _len, bool _val) const; protected: + public: /** * @brief 创建分配器 @@ -83,7 +84,7 @@ class FIRSTFIT : ALLOCATOR { * @param _addr 开始地址 * @param _len 长度,页 */ - FIRSTFIT(const char *_name, uintptr_t _addr, size_t _len); + FIRSTFIT(const char* _name, uintptr_t _addr, size_t _len); ~FIRSTFIT(void); @@ -101,26 +102,26 @@ class FIRSTFIT : ALLOCATOR { * @return true 成功 * @return false 失败 */ - bool alloc(uintptr_t _addr, size_t _len) override; + bool alloc(uintptr_t _addr, size_t _len) override; /** * @brief 释放 _addr 处 _len 页的内存 * @param _addr 要释放内存起点地址 * @param _len 页数 */ - void free(uintptr_t _addr, size_t _len) override; + void free(uintptr_t _addr, size_t _len) override; /** * @brief 获取已使用页数 * @return size_t 已经使用的页数 */ - size_t get_used_count(void) const override; + size_t get_used_count(void) const override; /** * @brief 获取未使用页数 * @return size_t 未使用的页数 */ - size_t get_free_count(void) const override; + size_t get_free_count(void) const override; }; -#endif /* _FIRTSTFIT_H_ */ +#endif /* SIMPLEKERNEL_FIRTSTFIT_H */ diff --git a/src/include/mem/heap.h b/src/include/mem/heap.h index cc01066b0..464083e65 100644 --- a/src/include/mem/heap.h +++ b/src/include/mem/heap.h @@ -14,13 +14,13 @@ * */ -#ifndef _HEAP_H_ -#define _HEAP_H_ +#ifndef SIMPLEKERNEL_HEAP_H +#define SIMPLEKERNEL_HEAP_H -#include "stdint.h" -#include "stddef.h" -#include "slab.h" #include "allocator.h" +#include "cstddef" +#include "cstdint" +#include "slab.h" /** * @brief 堆抽象 @@ -28,35 +28,50 @@ class HEAP { private: // 堆分配器 - ALLOCATOR *allocator; + ALLOCATOR* allocator_kernel; + ALLOCATOR* allocator_non_kernel; protected: + public: /** * @brief 获取单例 * @return HEAP& 静态对象 */ - static HEAP &get_instance(void); + static HEAP& get_instance(void); /** 初始化 * @brief 堆初始化 * @return true 成功 * @return false 失败 */ - bool init(void); + bool init(void); + + /** + * @brief 内核地址内存申请 + * @param _byte 要申请的 bytes + * @return void* 申请到的地址 + */ + void* kmalloc(size_t _byte); + + /** + * @brief 内核地址内存释放 + * @param _p 要释放的内存地址 + */ + void kfree(void* _p); /** * @brief 内存申请 * @param _byte 要申请的 bytes * @return void* 申请到的地址 */ - void *malloc(size_t _byte); + void* malloc(size_t _byte); /** * @brief 内存释放 * @param _p 要释放的内存地址 */ - void free(void *_p); + void free(void* _p); }; -#endif /* _HEAP_H_ */ +#endif /* SIMPLEKERNEL_HEAP_H */ diff --git a/src/include/mem/pmm.h b/src/include/mem/pmm.h index 190d1bca9..17e4a8c96 100644 --- a/src/include/mem/pmm.h +++ b/src/include/mem/pmm.h @@ -14,13 +14,13 @@ * */ -#ifndef _PMM_H_ -#define _PMM_H_ +#ifndef SIMPLEKERNEL_PMM_H +#define SIMPLEKERNEL_PMM_H -#include "stddef.h" -#include "stdint.h" -#include "firstfit.h" #include "allocator.h" +#include "cstddef" +#include "cstdint" +#include "firstfit.h" /** * @brief 物理内存管理接口 @@ -35,38 +35,39 @@ class PMM { private: /// 物理内存开始地址 - uintptr_t start; + uintptr_t start; /// 物理内存长度,单位为 bytes - size_t length; + size_t length; /// 物理内存页数 - size_t total_pages; + size_t total_pages; /// 内核空间起始地址 - uintptr_t kernel_space_start; + uintptr_t kernel_space_start; /// 内核空间大小,单位为 bytes - size_t kernel_space_length; + size_t kernel_space_length; /// 非内核空间起始地址 - uintptr_t non_kernel_space_start; + uintptr_t non_kernel_space_start; /// 非内核空间大小,单位为 bytes - size_t non_kernel_space_length; + size_t non_kernel_space_length; /// 内核空间不会位于内存中间,导致出现非内核空间被切割为两部分的情况 /// 物理内存分配器,分配内核空间 - ALLOCATOR *kernel_space_allocator; + ALLOCATOR* kernel_space_allocator; /// 物理内存分配器,分配非内核空间 - ALLOCATOR *allocator; + ALLOCATOR* allocator; /** * @brief 将 multiboot2/dtb 信息移动到内核空间 */ - void move_boot_info(void); + void move_boot_info(void); protected: + public: /** * @brief 获取单例 * @return PMM& 静态对象 */ - static PMM &get_instance(void); + static PMM& get_instance(void); /** * @brief 初始化 @@ -74,50 +75,62 @@ class PMM { * @return false 失败 * @todo 移动到构造函数去 */ - bool init(void); + bool init(void); /** * @brief 获取物理内存长度 * @return size_t 物理内存长度 */ - size_t get_pmm_length(void) const; + size_t get_pmm_length(void) const; + + /** + * @brief 获取内核空间起始地址 + * @return uintptr_t 内核空间起始地址 + */ + uintptr_t get_kernel_space_start(void) const; + + /** + * @brief 获取内核空间大小,单位为 byte + * @return size_t 内核空间大小 + */ + size_t get_kernel_space_length(void) const; /** * @brief 获取非内核空间起始地址 * @return uintptr_t 非内核空间起始地址 */ - uintptr_t get_non_kernel_space_start(void) const; + uintptr_t get_non_kernel_space_start(void) const; /** * @brief 获取非内核空间大小,单位为 byte * @return size_t 非内核空间大小 */ - size_t get_non_kernel_space_length(void) const; + size_t get_non_kernel_space_length(void) const; /** * @brief 获取当前已使用页数 * @return size_t 已使用页数 */ - size_t get_used_pages_count(void) const; + size_t get_used_pages_count(void) const; /** * @brief 获取当前空闲页 * @return size_t 空闲页数 */ - size_t get_free_pages_count(void) const; + size_t get_free_pages_count(void) const; /** * @brief 分配一页 * @return uintptr_t 分配的内存起始地址 */ - uintptr_t alloc_page(void); + uintptr_t alloc_page(void); /** * @brief 分配多页 * @param _len 页数 * @return uintptr_t 分配的内存起始地址 */ - uintptr_t alloc_pages(size_t _len); + uintptr_t alloc_pages(size_t _len); /** * @brief 分配以指定地址开始的 _len 页 @@ -126,20 +139,20 @@ class PMM { * @return true 成功 * @return false 失败 */ - bool alloc_pages(uintptr_t _addr, size_t _len); + bool alloc_pages(uintptr_t _addr, size_t _len); /** * @brief 在内核空间申请一页 * @return uintptr_t 分配的内存起始地址 */ - uintptr_t alloc_page_kernel(void); + uintptr_t alloc_page_kernel(void); /** * @brief 在内核空间分配 _len 页 * @param _len 页数 * @return uintptr_t 分配到的内存起始地址 */ - uintptr_t alloc_pages_kernel(size_t _len); + uintptr_t alloc_pages_kernel(size_t _len); /** * @brief 在内核空间分配以指定地址开始的 _len 页 @@ -148,20 +161,20 @@ class PMM { * @return true 成功 * @return false 失败 */ - bool alloc_pages_kernel(uintptr_t _addr, size_t _len); + bool alloc_pages_kernel(uintptr_t _addr, size_t _len); /** * @brief 回收一页 * @param _addr 要回收的地址 */ - void free_page(uintptr_t _addr); + void free_page(uintptr_t _addr); /** * @brief 回收多页 * @param _addr 要回收的地址 * @param _len 页数 */ - void free_pages(uintptr_t _addr, size_t _len); + void free_pages(uintptr_t _addr, size_t _len); }; -#endif /* _PMM_H_ */ +#endif /* SIMPLEKERNEL_PMM_H */ diff --git a/src/include/mem/slab.h b/src/include/mem/slab.h index 7489cb65b..a1b88c621 100644 --- a/src/include/mem/slab.h +++ b/src/include/mem/slab.h @@ -14,12 +14,13 @@ * */ -#ifndef _SLAB_H_ -#define _SLAB_H_ +#ifndef SIMPLEKERNEL_SLAB_H +#define SIMPLEKERNEL_SLAB_H -#include "stdint.h" -#include "stddef.h" #include "allocator.h" +#include "cstddef" +#include "cstdint" +#include "cstdio" #include "iostream" /** @@ -40,14 +41,14 @@ class SLAB : ALLOCATOR { /// 头节点标识 static constexpr const uintptr_t HEAD = 0xCDCD; // chunk_t 结构的物理地址 - uintptr_t addr; + uintptr_t addr; // 长度,不包括自身大小 单位为 byte // 记录的是实际使用的长度 // 按照 8byte 对齐 - size_t len; + size_t len; /// 双向循环链表指针 - chunk_t *prev; - chunk_t *next; + chunk_t* prev; + chunk_t* next; /** * @brief 构造函数只会在 SLAB 初始化时调用,且只用于构造头节点 @@ -60,23 +61,23 @@ class SLAB : ALLOCATOR { * @brief 插入新节点 * @param _new_node 要插入的节点 */ - void push_back(chunk_t *_new_node); + void push_back(chunk_t* _new_node); /** * @brief 获取链表长度 * @return size_t desc */ - size_t size(void) const; + size_t size(void) const; - bool operator==(const chunk_t &_node) const; - bool operator!=(const chunk_t &_node) const; + bool operator==(const chunk_t& _node) const; + bool operator!=(const chunk_t& _node) const; /** * @brief 返回相对头节点的第 _idx 项 * @param _idx 第几项 * @return chunk_t& chunk 对象 */ - chunk_t &operator[](size_t _idx) const; + chunk_t& operator[](size_t _idx) const; }; /** @@ -90,7 +91,7 @@ class SLAB : ALLOCATOR { * @param _list 目标链表 * @param _node 要移动的节点 */ - void move(chunk_t &_list, chunk_t *_node); + void move(chunk_t& _list, chunk_t* _node); /** * @brief 申请物理内存,返回申请到的地址起点,已经初始化过,且加入 free @@ -98,12 +99,12 @@ class SLAB : ALLOCATOR { * @param _len 要申请的长度 * @return chunk_t* 申请到的 chunk */ - chunk_t *alloc_pmm(size_t _len); + chunk_t* alloc_pmm(size_t _len); /** * @brief 释放内存 */ - void free_pmm(void); + void free_pmm(void); /** * @brief 分割一个节点 @@ -112,13 +113,13 @@ class SLAB : ALLOCATOR { * @note 如果剩余部分符合要求,新建节点并加入 part 链表 * 同时将 _node->len 设置为 _len */ - void split(chunk_t *_node, size_t _len); + void split(chunk_t* _node, size_t _len); /** * @brief 合并 part 中地址连续的链表项,如果有可回收的回调用 free_pmm * 进行回收 */ - void merge(void); + void merge(void); /** * @brief 在 _which 链表中查找长度符合的 @@ -127,34 +128,37 @@ class SLAB : ALLOCATOR { * @param _alloc 如果未找到是否分配 * @return chunk_t* 未找到返回 nullptr */ - chunk_t *find(chunk_t &_which, size_t _len, bool _alloc); + chunk_t* find(chunk_t& _which, size_t _len, bool _alloc); protected: + public: // 当前 cache 的长度,单位为 byte - size_t len; + size_t len; // 这三个作为头节点使用,不会实际使用 // full/part/free 是相对于 pmm // 分配的一个或多个连续的页而言的 // 已经分配的 len 长度的内存,当然 len 不一定全部使用,真实使用的长度由 // chunk 记录 - chunk_t full; + chunk_t full; // 申请的内存使用了一部分 - chunk_t part; + chunk_t part; // 一整段申请的内存都没有使用 - chunk_t free; + chunk_t free; + /// 管理的是否为内核地址 + bool is_kernel_space; // 查找长度符合的 - chunk_t *find(size_t _len); + chunk_t* find(size_t _len); /** * @brief 释放一个 full 的链表项 * @param _node 要释放的节点 */ - void remove(chunk_t *_node); + void remove(chunk_t* _node); - friend std::ostream &operator<<(std::ostream &_out, - SLAB::slab_cache_t &_cache) { + friend std::ostream& + operator<<(std::ostream& _out, SLAB::slab_cache_t& _cache) { printf("_cache.full.size(): 0x%X\n", _cache.full.size()); for (size_t i = 0; i < _cache.full.size(); i++) { printf("full 0x%X addr: 0x%X, len: 0x%X\n", i, @@ -194,29 +198,34 @@ class SLAB : ALLOCATOR { }; /// 最小为 256 bytes - static constexpr const size_t MIN = 256; - static constexpr const size_t SHIFT = 8; + static constexpr const size_t MIN = 256; + static constexpr const size_t SHIFT = 8; /// 支持 256(256<<(CACHAE_LEN-1)) bytes /// slab_cache[0] 即为内存为 256 字节的 chunk_t 结构链表 static constexpr const size_t CACHAE_LEN = 9; slab_cache_t slab_cache[CACHAE_LEN]; + /// 管理的是否为内核地址 + bool is_kernel_space; + /** * @brief 根据 _len 获取对应的 slab_cache 下标 * @param _len 长度 * @return size_t 对应的下标 */ - size_t get_idx(size_t _len) const; + size_t get_idx(size_t _len) const; protected: + public: /** * @brief 构造函数 * @param _name 分配器名称 * @param _addr 管理地址起始 * @param _len 要管理的长度 + * @param _is_kernel 管理的是否为内核地址 */ - SLAB(const char *_name, uintptr_t _addr, size_t _len); + SLAB(const char* _name, uintptr_t _addr, size_t _len, bool _is_kernel); ~SLAB(void); @@ -228,18 +237,18 @@ class SLAB : ALLOCATOR { uintptr_t alloc(size_t _len) override; // slab 不支持这个函数 - bool alloc(uintptr_t _addr, size_t _len) override; + bool alloc(uintptr_t _addr, size_t _len) override; /** * @brief 释放内存 * @param _addr 要释放的地址 * @note slab 不使用第二个参数 */ - void free(uintptr_t _addr, size_t) override; + void free(uintptr_t _addr, size_t) override; // 暂时不支持 - size_t get_used_count(void) const override; - size_t get_free_count(void) const override; + size_t get_used_count(void) const override; + size_t get_free_count(void) const override; }; -#endif /* _SLAB_H_ */ +#endif /* SIMPLEKERNEL_SLAB_H */ diff --git a/src/include/mem/vmm.h b/src/include/mem/vmm.h index 964fa6825..27fbdb446 100644 --- a/src/include/mem/vmm.h +++ b/src/include/mem/vmm.h @@ -14,105 +14,106 @@ * */ -#ifndef _VMM_H_ -#define _VMM_H_ +#ifndef SIMPLEKERNEL_VMM_H +#define SIMPLEKERNEL_VMM_H -#include "limits.h" +#include "climits" #include "common.h" +#include "cpu.hpp" // TODO: 可以优化 /// 页表项,最底层 -typedef uintptr_t pte_t; +typedef uintptr_t pte_t; /// 页表,也可以是页目录,它们的结构是一样的 -typedef uintptr_t *pt_t; +typedef uintptr_t* pt_t; /// 每个页表能映射多少页 = 页大小/页表项大小: 2^9 -static constexpr const size_t VMM_PAGES_PRE_PAGE_TABLE = - COMMON::PAGE_SIZE / sizeof(pte_t); +static constexpr const size_t VMM_PAGES_PRE_PAGE_TABLE + = COMMON::PAGE_SIZE / sizeof(pte_t); /// 映射内核空间的大小 static constexpr const size_t VMM_KERNEL_SPACE_SIZE = COMMON::KERNEL_SPACE_SIZE; /// 内核映射的页数 -static constexpr const size_t VMM_KERNEL_SPACE_PAGES = - VMM_KERNEL_SPACE_SIZE / COMMON::PAGE_SIZE; +static constexpr const size_t VMM_KERNEL_SPACE_PAGES + = VMM_KERNEL_SPACE_SIZE / COMMON::PAGE_SIZE; #if defined(__i386__) /// P = 1 表示有效; P = 0 表示无效。 -static constexpr const uint8_t VMM_PAGE_VALID = 1 << 0; +static constexpr const uint8_t VMM_PAGE_VALID = 1 << 0; /// 如果为 0 表示页面只读或可执行。 static constexpr const uint8_t VMM_PAGE_READABLE = 0; static constexpr const uint8_t VMM_PAGE_WRITABLE = 1 << 1; static constexpr const uint8_t VMM_PAGE_EXECUTABLE = 0; /// U/S-- 位 2 是用户 / 超级用户 (User/Supervisor) 标志。 /// 如果为 1 那么运行在任何特权级上的程序都可以访问该页面。 -static constexpr const uint8_t VMM_PAGE_USER = 1 << 2; +static constexpr const uint8_t VMM_PAGE_USER = 1 << 2; /// 内核虚拟地址相对物理地址的偏移 -static constexpr const size_t KERNEL_OFFSET = 0x0; +static constexpr const size_t KERNEL_OFFSET = 0x0; /// PTE 属性位数 -static constexpr const size_t VMM_PTE_PROP_BITS = 12; +static constexpr const size_t VMM_PTE_PROP_BITS = 12; /// PTE 页内偏移位数 -static constexpr const size_t VMM_PAGE_OFF_BITS = 12; +static constexpr const size_t VMM_PAGE_OFF_BITS = 12; /// VPN 位数 -static constexpr const size_t VMM_VPN_BITS = 10; +static constexpr const size_t VMM_VPN_BITS = 10; /// VPN 位数掩码,10 位 VPN -static constexpr const size_t VMM_VPN_BITS_MASK = 0x3FF; +static constexpr const size_t VMM_VPN_BITS_MASK = 0x3FF; /// i386 使用了两级页表 -static constexpr const size_t VMM_PT_LEVEL = 2; +static constexpr const size_t VMM_PT_LEVEL = 2; #elif defined(__x86_64__) /// P = 1 表示有效; P = 0 表示无效。 -static constexpr const uint8_t VMM_PAGE_VALID = 1 << 0; +static constexpr const uint8_t VMM_PAGE_VALID = 1 << 0; /// 如果为 0 表示页面只读或可执行。 static constexpr const uint8_t VMM_PAGE_READABLE = 0; static constexpr const uint8_t VMM_PAGE_WRITABLE = 1 << 1; static constexpr const uint8_t VMM_PAGE_EXECUTABLE = 0; /// U/S-- 位 2 是用户 / 超级用户 (User/Supervisor) 标志。 /// 如果为 1 那么运行在任何特权级上的程序都可以访问该页面。 -static constexpr const uint8_t VMM_PAGE_USER = 1 << 2; +static constexpr const uint8_t VMM_PAGE_USER = 1 << 2; /// 内核虚拟地址相对物理地址的偏移 -static constexpr const size_t KERNEL_OFFSET = 0x0; +static constexpr const size_t KERNEL_OFFSET = 0x0; /// PTE 属性位数 -static constexpr const size_t VMM_PTE_PROP_BITS = 12; +static constexpr const size_t VMM_PTE_PROP_BITS = 12; /// PTE 页内偏移位数 -static constexpr const size_t VMM_PAGE_OFF_BITS = 12; +static constexpr const size_t VMM_PAGE_OFF_BITS = 12; /// VPN 位数 -static constexpr const size_t VMM_VPN_BITS = 9; +static constexpr const size_t VMM_VPN_BITS = 9; /// VPN 位数掩码,9 位 VPN -static constexpr const size_t VMM_VPN_BITS_MASK = 0x1FF; +static constexpr const size_t VMM_VPN_BITS_MASK = 0x1FF; /// x86_64 使用了四级页表 -static constexpr const size_t VMM_PT_LEVEL = 4; +static constexpr const size_t VMM_PT_LEVEL = 4; #elif defined(__riscv) /// 有效位 -static constexpr const uint8_t VMM_PAGE_VALID = 1 << 0; +static constexpr const uint8_t VMM_PAGE_VALID = CPU::pte_t::VALID; /// 可读位 -static constexpr const uint8_t VMM_PAGE_READABLE = 1 << 1; -/// 可写位 -static constexpr const uint8_t VMM_PAGE_WRITABLE = 1 << 2; +static constexpr const uint8_t VMM_PAGE_READABLE = CPU::pte_t::READ; +/// 可写位s +static constexpr const uint8_t VMM_PAGE_WRITABLE = CPU::pte_t::WRITE; /// 可执行位 -static constexpr const uint8_t VMM_PAGE_EXECUTABLE = 1 << 3; +static constexpr const uint8_t VMM_PAGE_EXECUTABLE = CPU::pte_t::EXEC; /// 用户位 -static constexpr const uint8_t VMM_PAGE_USER = 1 << 4; +static constexpr const uint8_t VMM_PAGE_USER = CPU::pte_t::USER; /// 全局位,我们不会使用 -static constexpr const uint8_t VMM_PAGE_GLOBAL = 1 << 5; +static constexpr const uint8_t VMM_PAGE_GLOBAL = CPU::pte_t::GLOBAL; /// 已使用位,用于替换算法 -static constexpr const uint8_t VMM_PAGE_ACCESSED = 1 << 6; +static constexpr const uint8_t VMM_PAGE_ACCESSED = CPU::pte_t::ACCESSED; /// 已修改位,用于替换算法 -static constexpr const uint8_t VMM_PAGE_DIRTY = 1 << 7; +static constexpr const uint8_t VMM_PAGE_DIRTY = CPU::pte_t::DIRTY; /// 内核虚拟地址相对物理地址的偏移 -static constexpr const size_t KERNEL_OFFSET = 0x0; +static constexpr const size_t KERNEL_OFFSET = 0x0; /// PTE 属性位数 -static constexpr const size_t VMM_PTE_PROP_BITS = 10; +static constexpr const size_t VMM_PTE_PROP_BITS = 10; /// PTE 页内偏移位数 -static constexpr const size_t VMM_PAGE_OFF_BITS = 12; +static constexpr const size_t VMM_PAGE_OFF_BITS = 12; /// VPN 位数 -static constexpr const size_t VMM_VPN_BITS = 9; +static constexpr const size_t VMM_VPN_BITS = 9; /// VPN 位数掩码,9 位 VPN -static constexpr const size_t VMM_VPN_BITS_MASK = 0x1FF; +static constexpr const size_t VMM_VPN_BITS_MASK = 0x1FF; /// riscv64 使用了三级页表 -static constexpr const size_t VMM_PT_LEVEL = 3; +static constexpr const size_t VMM_PT_LEVEL = 3; #endif /** @@ -184,34 +185,35 @@ class VMM { * @param _alloc 是否分配 * @return pte_t* 未找到返回 nullptr */ - pte_t *find(const pt_t _pgd, uintptr_t _va, bool _alloc); + pte_t* find(const pt_t _pgd, uintptr_t _va, bool _alloc); protected: + public: /** * @brief 获取单例 * @return VMM& 静态对象 */ - static VMM &get_instance(void); + static VMM& get_instance(void); /** * @brief 初始化 * @return true 成功 * @return false 失败 */ - bool init(void); + bool init(void); /** * @brief 获取当前页目录 * @return pt_t 当前页目录 */ - pt_t get_pgd(void); + pt_t get_pgd(void); /** * @brief 设置当前页目录 * @param _pgd 要设置的页目录 */ - void set_pgd(const pt_t _pgd); + void set_pgd(const pt_t _pgd); /** * @brief 映射物理地址到虚拟地址 @@ -237,7 +239,7 @@ class VMM { * @return true 已映射 * @return false 未映射 */ - bool get_mmap(const pt_t _pgd, uintptr_t _va, const void *_pa); + bool get_mmap(const pt_t _pgd, uintptr_t _va, const void* _pa); }; -#endif /* _VMM_H */ +#endif /* SIMPLEKERNEL_VMM_H */ diff --git a/src/include/resource.h b/src/include/resource.h index d82f681fa..1db61684b 100644 --- a/src/include/resource.h +++ b/src/include/resource.h @@ -14,12 +14,12 @@ * */ -#ifndef _RESOURCE_H_ -#define _RESOURCE_H_ +#ifndef SIMPLEKERNEL_RESOURCE_H +#define SIMPLEKERNEL_RESOURCE_H -#include "stdint.h" +#include "cassert" +#include "cstdint" #include "iostream" -#include "assert.h" /** * @brief 用于表示一种资源 @@ -28,18 +28,21 @@ struct resource_t { /// 资源类型 enum : uint8_t { /// 内存 - MEM = 1 << 0, + MEM = 1 << 0, /// 中断号 INTR_NO = 1 << 1, }; + uint8_t type; /// 资源名称 - char *name; + char* name; + /// 内存信息 struct { uintptr_t addr; size_t len; } mem; + /// 中断号 uint8_t intr_no; @@ -56,7 +59,7 @@ struct resource_t { * @param _res 要输出的 resource_t * @return std::ostream& 输出流 */ - friend std::ostream &operator<<(std::ostream &_os, const resource_t &_res) { + friend std::ostream& operator<<(std::ostream& _os, const resource_t& _res) { printf("%s: ", _res.name); if (_res.type & MEM) { printf("MEM(0x%p, 0x%p)", _res.mem.addr, _res.mem.len); @@ -68,4 +71,4 @@ struct resource_t { } }; -#endif /* _RESOURCE_H_ */ +#endif /* SIMPLEKERNEL_RESOURCE_H */ diff --git a/src/kernel/allocator.cpp b/src/kernel/allocator.cpp index dbfd049dc..40b447b3b 100644 --- a/src/kernel/allocator.cpp +++ b/src/kernel/allocator.cpp @@ -14,13 +14,11 @@ * */ -#include "stddef.h" -#include "stdint.h" -#include "assert.h" -#include "common.h" #include "allocator.h" +#include "cstddef" +#include "cstdint" -ALLOCATOR::ALLOCATOR(const char *_name, uintptr_t _addr, size_t _len) { +ALLOCATOR::ALLOCATOR(const char* _name, uintptr_t _addr, size_t _len) { // 默认名字 name = _name; allocator_start_addr = _addr; diff --git a/src/kernel/firstfit.cpp b/src/kernel/firstfit.cpp index 943e94ff9..9b97f06b5 100644 --- a/src/kernel/firstfit.cpp +++ b/src/kernel/firstfit.cpp @@ -14,11 +14,11 @@ * */ -#include "stdint.h" -#include "string.h" -#include "pmm.h" -#include "stdio.h" #include "firstfit.h" +#include "common.h" +#include "cstdint" +#include "cstdio" +#include "cstring" void FIRSTFIT::set(size_t _idx) { map[_idx >> SHIFT] |= (uintptr_t)1 << (_idx & MASK); @@ -53,7 +53,7 @@ size_t FIRSTFIT::find_len(size_t _len, bool _val) const { return ~(size_t)0; } -FIRSTFIT::FIRSTFIT(const char *_name, uintptr_t _addr, size_t _len) +FIRSTFIT::FIRSTFIT(const char* _name, uintptr_t _addr, size_t _len) : ALLOCATOR(_name, _addr, _len) { // 所有清零 bzero(map, sizeof(map)); @@ -70,7 +70,7 @@ FIRSTFIT::~FIRSTFIT(void) { uintptr_t FIRSTFIT::alloc(size_t _len) { uintptr_t res_addr = 0; // 在位图中寻找连续 _len 的位置 - size_t idx = find_len(_len, false); + size_t idx = find_len(_len, false); // 如果为 ~0 说明未找到 if (idx == ~(size_t)0) { // err("NO ENOUGH MEM.\n"); @@ -83,7 +83,7 @@ uintptr_t FIRSTFIT::alloc(size_t _len) { } // 计算实际地址 // 分配器起始地址+页长度*第几页 - res_addr = allocator_start_addr + (COMMON::PAGE_SIZE * idx); + res_addr = allocator_start_addr + (COMMON::PAGE_SIZE * idx); // 更新统计信息 allocator_free_count -= _len; allocator_used_count += _len; @@ -92,9 +92,9 @@ uintptr_t FIRSTFIT::alloc(size_t _len) { bool FIRSTFIT::alloc(uintptr_t _addr, size_t _len) { // _addr 不在管理范围内 - if ((_addr < allocator_start_addr) || - (_addr >= - allocator_start_addr + allocator_length * COMMON::PAGE_SIZE)) { + if ((_addr < allocator_start_addr) + || (_addr + >= allocator_start_addr + allocator_length * COMMON::PAGE_SIZE)) { return false; } // 计算 _addr 在 map 中的索引 @@ -120,9 +120,9 @@ bool FIRSTFIT::alloc(uintptr_t _addr, size_t _len) { void FIRSTFIT::free(uintptr_t _addr, size_t _len) { // _addr 不在管理范围内 - if ((_addr < allocator_start_addr) || - (_addr >= - allocator_start_addr + allocator_length * COMMON::PAGE_SIZE)) { + if ((_addr < allocator_start_addr) + || (_addr + >= allocator_start_addr + allocator_length * COMMON::PAGE_SIZE)) { return; } // 计算 _addr 在 map 中的索引 diff --git a/src/kernel/heap.cpp b/src/kernel/heap.cpp index 40b4a90f0..dfbb6a156 100644 --- a/src/kernel/heap.cpp +++ b/src/kernel/heap.cpp @@ -14,35 +14,72 @@ * */ -#include "stdio.h" +#include "heap.h" #include "common.h" +#include "cstdio" #include "pmm.h" -#include "heap.h" -HEAP &HEAP::get_instance(void) { +HEAP& HEAP::get_instance(void) { /// 定义全局 HEAP 对象 static HEAP heap; return heap; } bool HEAP::init(void) { - static SLAB slab_allocator( - "SLAB Allocator", PMM::get_instance().get_non_kernel_space_start(), - PMM::get_instance().get_non_kernel_space_length() * COMMON::PAGE_SIZE); - allocator = (ALLOCATOR *)&slab_allocator; + // 内核空间 + static SLAB slab_allocator_kernel( + "SLAB Allocator Kernel", PMM::get_instance().get_kernel_space_start(), + PMM::get_instance().get_kernel_space_length() * COMMON::PAGE_SIZE, true); + allocator_kernel = (ALLOCATOR*)&slab_allocator_kernel; + // 非内核空间 + static SLAB slab_allocator_non_kernel( + "SLAB Allocator", PMM::get_instance().get_non_kernel_space_start(), + PMM::get_instance().get_non_kernel_space_length() * COMMON::PAGE_SIZE, + false); + allocator_non_kernel = (ALLOCATOR*)&slab_allocator_non_kernel; info("heap init.\n"); return 0; } -void *HEAP::malloc(size_t _byte) { - void *ret = nullptr; - ret = (void *)allocator->alloc(_byte); +void* HEAP::kmalloc(size_t _byte) { + void* ret = nullptr; + ret = (void*)allocator_kernel->alloc(_byte); return ret; } -void HEAP::free(void *_addr) { +void HEAP::kfree(void* _addr) { // 堆不需要 _len 参数 - allocator->free((uintptr_t)_addr, 0); + allocator_kernel->free((uintptr_t)_addr, 0); + return; +} + +void* HEAP::malloc(size_t _byte) { + void* ret = nullptr; + ret = (void*)allocator_non_kernel->alloc(_byte); + return ret; +} + +void HEAP::free(void* _addr) { + // 堆不需要 _len 参数 + allocator_non_kernel->free((uintptr_t)_addr, 0); + return; +} + +/** + * @brief 分配内核空间内存 + * @param _size 要申请的 bytes + * @return void* 申请到的地址 + */ +extern "C" void* kmalloc(size_t _size) { + return (void*)HEAP::get_instance().kmalloc(_size); +} + +/** + * @brief 释放内核空间内存 + * @param _p 要释放的内存地址 + */ +extern "C" void kfree(void* _p) { + HEAP::get_instance().kfree(_p); return; } @@ -51,15 +88,15 @@ void HEAP::free(void *_addr) { * @param _size 要申请的 bytes * @return void* 申请到的地址 */ -extern "C" void *malloc(size_t _size) { - return (void *)HEAP::get_instance().malloc(_size); +extern "C" void* malloc(size_t _size) { + return (void*)HEAP::get_instance().malloc(_size); } /** * @brief free 定义 * @param _p 要释放的内存地址 */ -extern "C" void free(void *_p) { +extern "C" void free(void* _p) { HEAP::get_instance().free(_p); return; } diff --git a/src/kernel/include/kernel.h b/src/kernel/include/kernel.h index 293f8d1fe..32361ecca 100644 --- a/src/kernel/include/kernel.h +++ b/src/kernel/include/kernel.h @@ -14,8 +14,8 @@ * */ -#ifndef _KERNEL_H_ -#define _KERNEL_H_ +#ifndef SIMPLEKERNEL_KERNEL_H +#define SIMPLEKERNEL_KERNEL_H /** * @brief 声明 kernel_main 用 C 方法编译 @@ -27,23 +27,29 @@ extern "C" void kernel_main(void); * @brief 物理内存测试函数 * @return int 0 成功 */ -int test_pmm(void); +int test_pmm(void); /** * @brief 虚拟内存测试函数 * @return int 0 成功 */ -int test_vmm(void); +int test_vmm(void); /** * @brief 堆测试函数 - * @return int desc + * @return int 0 成功 + */ +int test_heap(void); + +/** + * @brief 中断测试函数 + * @return int 0 成功 */ -int test_heap(void); +int test_intr(void); /** * @brief 输出系统信息 */ -void show_info(void); +void show_info(void); -#endif /* _KERNEL_H_ */ +#endif /* SIMPLEKERNEL_KERNEL_H */ diff --git a/src/kernel/io.cpp b/src/kernel/io.cpp index fe6329c02..66ad0d6e6 100644 --- a/src/kernel/io.cpp +++ b/src/kernel/io.cpp @@ -1,20 +1,28 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// io.cpp for Simple-XX/SimpleKernel. -// IO 接口实现 - -#include "stddef.h" -#include "stdarg.h" -#include "string.h" +/** + * @file io.cpp + * @brief IO 接口实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#include "cstdarg" +#include "cstring" #ifndef __riscv -#include "port.h" +# include "port.h" #endif +#include "cstdio" #include "io.h" -#include "stdio.h" -IO &IO::get_instance(void) { +IO& IO::get_instance(void) { /// 定义全局 IO 对象 static IO io; return io; @@ -51,39 +59,39 @@ void IO::outd(const uint32_t port, const uint32_t data) { #endif // MMIO 实现 -uint8_t IO::read8(void *_addr) { - return *(uint8_t *)_addr; +uint8_t IO::read8(void* _addr) { + return *(uint8_t*)_addr; } -void IO::write8(void *_addr, uint8_t _val) { - *(uint8_t *)_addr = _val; +void IO::write8(void* _addr, uint8_t _val) { + *(uint8_t*)_addr = _val; return; } -uint16_t IO::read16(void *_addr) { - return *(uint16_t *)_addr; +uint16_t IO::read16(void* _addr) { + return *(uint16_t*)_addr; } -void IO::write16(void *_addr, uint16_t _val) { - *(uint16_t *)_addr = _val; +void IO::write16(void* _addr, uint16_t _val) { + *(uint16_t*)_addr = _val; return; } -uint32_t IO::read32(void *_addr) { - return *(uint32_t *)_addr; +uint32_t IO::read32(void* _addr) { + return *(uint32_t*)_addr; } -void IO::write32(void *_addr, uint32_t _val) { - *(uint32_t *)_addr = _val; +void IO::write32(void* _addr, uint32_t _val) { + *(uint32_t*)_addr = _val; return; } -uint64_t IO::read64(void *_addr) { - return *(uint64_t *)_addr; +uint64_t IO::read64(void* _addr) { + return *(uint64_t*)_addr; } -void IO::write64(void *_addr, uint64_t _val) { - *(uint64_t *)_addr = _val; +void IO::write64(void* _addr, uint64_t _val) { + *(uint64_t*)_addr = _val; return; } @@ -104,20 +112,20 @@ void IO::put_char(char c) { return; } -int32_t IO::write_string(const char *s) { +int32_t IO::write_string(const char* s) { io.write_string(s); return 0; } /// 输出缓冲区 -char buf[IO::BUF_SIZE]; +char buf[IO::BUF_SIZE]; /** * @brief printf 定义 * @param _fmt 格式化字符串 * @return int32_t 输出的长度 */ -extern "C" int32_t printf(const char *_fmt, ...) { +extern "C" int32_t printf(const char* _fmt, ...) { va_list va; va_start(va, _fmt); // 交给 src/libc/src/stdio/vsprintf.c 中的 _vsnprintf @@ -134,13 +142,13 @@ extern "C" int32_t printf(const char *_fmt, ...) { /** * @brief 与 printf 类似,只是颜色不同 */ -extern "C" int32_t info(const char *_fmt, ...) { +extern "C" int32_t info(const char* _fmt, ...) { COLOR::color_t curr_color = IO::get_instance().get_color(); IO::get_instance().set_color(COLOR::CYAN); va_list va; int32_t i; va_start(va, _fmt); - i = vsnprintf_(buf, (size_t)-1, _fmt, va); + i = vsnprintf_(buf, IO::BUF_SIZE, _fmt, va); va_end(va); IO::get_instance().write_string(buf); bzero(buf, IO::BUF_SIZE); @@ -151,13 +159,13 @@ extern "C" int32_t info(const char *_fmt, ...) { /** * @brief 与 printf 类似,只是颜色不同 */ -extern "C" int32_t warn(const char *_fmt, ...) { +extern "C" int32_t warn(const char* _fmt, ...) { COLOR::color_t curr_color = IO::get_instance().get_color(); IO::get_instance().set_color(COLOR::YELLOW); va_list va; int32_t i; va_start(va, _fmt); - i = vsnprintf_(buf, (size_t)-1, _fmt, va); + i = vsnprintf_(buf, IO::BUF_SIZE, _fmt, va); va_end(va); IO::get_instance().write_string(buf); bzero(buf, IO::BUF_SIZE); @@ -168,13 +176,13 @@ extern "C" int32_t warn(const char *_fmt, ...) { /** * @brief 与 printf 类似,只是颜色不同 */ -extern "C" int32_t err(const char *_fmt, ...) { +extern "C" int32_t err(const char* _fmt, ...) { COLOR::color_t curr_color = IO::get_instance().get_color(); IO::get_instance().set_color(COLOR::LIGHT_RED); va_list va; int32_t i; va_start(va, _fmt); - i = vsnprintf_(buf, (size_t)-1, _fmt, va); + i = vsnprintf_(buf, IO::BUF_SIZE, _fmt, va); va_end(va); IO::get_instance().write_string(buf); bzero(buf, IO::BUF_SIZE); diff --git a/src/kernel/kernel_main.cpp b/src/kernel/kernel_main.cpp index 81aade5de..fe66c4883 100644 --- a/src/kernel/kernel_main.cpp +++ b/src/kernel/kernel_main.cpp @@ -14,23 +14,18 @@ * */ -#include "cxxabi.h" -#include "common.h" -#include "stdio.h" -#include "stdlib.h" -#include "iostream" -#include "assert.h" #include "boot_info.h" -#include "pmm.h" -#include "vmm.h" +#include "cassert" +#include "common.h" +#include "cpu.hpp" +#include "cstdio" +#include "cstdlib" #include "heap.h" #include "intr.h" -#include "cpu.hpp" +#include "iostream" #include "kernel.h" -#include "dtb.h" - -/// @todo gdb 调试 -/// @todo clion 环境 +#include "pmm.h" +#include "vmm.h" /** * @brief 内核主要逻辑 @@ -54,6 +49,8 @@ void kernel_main(void) { test_heap(); // 中断初始化 INTR::get_instance().init(); + // 测试中断 + test_intr(); // 时钟中断初始化 TIMER::get_instance().init(); // 允许中断 @@ -76,10 +73,10 @@ void show_info(void) { // 内核实际大小 auto kernel_size = COMMON::KERNEL_END_ADDR - COMMON::KERNEL_START_ADDR; // 内核实际占用页数 - auto kernel_pages = - (COMMON::ALIGN(COMMON::KERNEL_END_ADDR, COMMON::PAGE_SIZE) - - COMMON::ALIGN(COMMON::KERNEL_START_ADDR, COMMON::PAGE_SIZE)) / - COMMON::PAGE_SIZE; + auto kernel_pages + = (COMMON::ALIGN(COMMON::KERNEL_END_ADDR, COMMON::PAGE_SIZE) + - COMMON::ALIGN(COMMON::KERNEL_START_ADDR, COMMON::PAGE_SIZE)) + / COMMON::PAGE_SIZE; info("Kernel start: 0x%p, end 0x%p, size: 0x%X bytes, 0x%X pages.\n", COMMON::KERNEL_START_ADDR, COMMON::KERNEL_END_ADDR, kernel_size, kernel_pages); diff --git a/src/kernel/pmm.cpp b/src/kernel/pmm.cpp index 09fd7a424..8225724ad 100644 --- a/src/kernel/pmm.cpp +++ b/src/kernel/pmm.cpp @@ -14,13 +14,13 @@ * */ -#include "stdio.h" -#include "string.h" -#include "assert.h" -#include "common.h" +#include "pmm.h" #include "boot_info.h" +#include "cassert" +#include "common.h" +#include "cstdio" +#include "cstring" #include "resource.h" -#include "pmm.h" // 将启动信息移动到内核空间 void PMM::move_boot_info(void) { @@ -32,7 +32,7 @@ void PMM::move_boot_info(void) { // 申请空间 uintptr_t new_addr = get_instance().alloc_pages_kernel(pages); // 复制过来,完成后以前的内存就可以使用了 - memcpy((void *)new_addr, (void *)BOOT_INFO::boot_info_addr, + memcpy((void*)new_addr, (void*)BOOT_INFO::boot_info_addr, pages * COMMON::PAGE_SIZE); // 设置地址 BOOT_INFO::boot_info_addr = (uintptr_t)new_addr; @@ -41,7 +41,7 @@ void PMM::move_boot_info(void) { return; } -PMM &PMM::get_instance(void) { +PMM& PMM::get_instance(void) { /// 定义全局 PMM 对象 static PMM pmm; return pmm; @@ -51,46 +51,47 @@ bool PMM::init(void) { // 获取物理内存信息 resource_t mem_info = BOOT_INFO::get_memory(); // 设置物理地址的起点与长度 - start = mem_info.mem.addr; - length = mem_info.mem.len; + start = mem_info.mem.addr; + length = mem_info.mem.len; // 计算页数 - total_pages = length / COMMON::PAGE_SIZE; + total_pages = length / COMMON::PAGE_SIZE; // 内核空间地址开始 - kernel_space_start = COMMON::KERNEL_START_ADDR; + kernel_space_start = COMMON::KERNEL_START_ADDR; // 长度手动指定 kernel_space_length = COMMON::KERNEL_SPACE_SIZE; // 非内核空间在内核空间结束后 - non_kernel_space_start = - COMMON::KERNEL_START_ADDR + COMMON::KERNEL_SPACE_SIZE; + non_kernel_space_start + = COMMON::KERNEL_START_ADDR + COMMON::KERNEL_SPACE_SIZE; // 长度为总长度减去内核长度 non_kernel_space_length = length - kernel_space_length; // 创建分配器 // 内核空间 static FIRSTFIT first_fit_allocator_kernel( - "First Fit Allocator(kernel space)", kernel_space_start, - kernel_space_length / COMMON::PAGE_SIZE); - kernel_space_allocator = (ALLOCATOR *)&first_fit_allocator_kernel; - + "First Fit Allocator(kernel space)", kernel_space_start, + kernel_space_length / COMMON::PAGE_SIZE); + kernel_space_allocator = (ALLOCATOR*)&first_fit_allocator_kernel; // 非内核空间 - static FIRSTFIT first_fit_allocator( - "First Fit Allocator", non_kernel_space_start, - non_kernel_space_length / COMMON::PAGE_SIZE); - allocator = (ALLOCATOR *)&first_fit_allocator; + static FIRSTFIT first_fit_allocator("First Fit Allocator", + non_kernel_space_start, + non_kernel_space_length + / COMMON::PAGE_SIZE); + allocator = (ALLOCATOR*)&first_fit_allocator; // 内核实际占用页数 这里也算了 0~1M 的 reserved 内存 - size_t kernel_pages = - (COMMON::ALIGN(COMMON::KERNEL_END_ADDR, COMMON::PAGE_SIZE) - - COMMON::ALIGN(COMMON::KERNEL_START_ADDR, COMMON::PAGE_SIZE)) / - COMMON::PAGE_SIZE; + size_t kernel_pages + = (COMMON::ALIGN(COMMON::KERNEL_END_ADDR, COMMON::PAGE_SIZE) + - COMMON::ALIGN(COMMON::KERNEL_START_ADDR, COMMON::PAGE_SIZE)) + / COMMON::PAGE_SIZE; // 将内核已使用部分划分出来 if (alloc_pages_kernel(COMMON::KERNEL_START_ADDR, kernel_pages) == true) { // 将 multiboot2/dtb 信息移动到内核空间 - get_instance().move_boot_info(); + move_boot_info(); info("pmm init.\n"); return true; } else { + assert(0); return false; } } @@ -99,6 +100,14 @@ size_t PMM::get_pmm_length(void) const { return length; } +uintptr_t PMM::get_kernel_space_start(void) const { + return kernel_space_start; +} + +size_t PMM::get_kernel_space_length(void) const { + return kernel_space_length; +} + uintptr_t PMM::get_non_kernel_space_start(void) const { return non_kernel_space_start; } @@ -108,14 +117,14 @@ size_t PMM::get_non_kernel_space_length(void) const { } size_t PMM::get_used_pages_count(void) const { - size_t ret = - kernel_space_allocator->get_used_count() + allocator->get_used_count(); + size_t ret + = kernel_space_allocator->get_used_count() + allocator->get_used_count(); return ret; } size_t PMM::get_free_pages_count(void) const { - size_t ret = - kernel_space_allocator->get_free_count() + allocator->get_free_count(); + size_t ret + = kernel_space_allocator->get_free_count() + allocator->get_free_count(); return ret; } @@ -151,12 +160,12 @@ bool PMM::alloc_pages_kernel(uintptr_t _addr, size_t _len) { void PMM::free_page(uintptr_t _addr) { // 判断应该使用哪个分配器 - if (_addr >= kernel_space_start && - _addr < kernel_space_start + kernel_space_length) { + if (_addr >= kernel_space_start + && _addr < kernel_space_start + kernel_space_length) { kernel_space_allocator->free(_addr, 1); } - else if (_addr >= non_kernel_space_start && - _addr < non_kernel_space_start + non_kernel_space_length) { + else if (_addr >= non_kernel_space_start + && _addr < non_kernel_space_start + non_kernel_space_length) { allocator->free(_addr, 1); } else { @@ -168,12 +177,12 @@ void PMM::free_page(uintptr_t _addr) { void PMM::free_pages(uintptr_t _addr, size_t _len) { // 判断应该使用哪个分配器 - if (_addr >= kernel_space_start && - _addr < kernel_space_start + kernel_space_length) { + if (_addr >= kernel_space_start + && _addr < kernel_space_start + kernel_space_length) { kernel_space_allocator->free(_addr, _len); } - else if (_addr >= non_kernel_space_start && - _addr < non_kernel_space_start + non_kernel_space_length) { + else if (_addr >= non_kernel_space_start + && _addr < non_kernel_space_start + non_kernel_space_length) { allocator->free(_addr, _len); } // 如果都不是说明有问题 diff --git a/src/kernel/slab.cpp b/src/kernel/slab.cpp index 9b6b08b9f..2ef5f6007 100644 --- a/src/kernel/slab.cpp +++ b/src/kernel/slab.cpp @@ -14,12 +14,12 @@ * */ -#include "stdio.h" -#include "string.h" +#include "slab.h" #include "assert.h" +#include "cstdio" #include "pmm.h" +#include "string.h" #include "vmm.h" -#include "slab.h" SLAB::chunk_t::chunk_t(void) { addr = HEAD; @@ -35,7 +35,7 @@ SLAB::chunk_t::~chunk_t(void) { size_t SLAB::chunk_t::size(void) const { size_t res = 0; - chunk_t *tmp = this->next; + chunk_t* tmp = this->next; while (tmp != this) { res++; tmp = tmp->next; @@ -43,22 +43,22 @@ size_t SLAB::chunk_t::size(void) const { return res; } -bool SLAB::chunk_t::operator==(const chunk_t &_node) const { - return addr == _node.addr && len == _node.len && prev == _node.prev && - next == _node.next; +bool SLAB::chunk_t::operator==(const chunk_t& _node) const { + return addr == _node.addr && len == _node.len && prev == _node.prev + && next == _node.next; } -bool SLAB::chunk_t::operator!=(const chunk_t &_node) const { - return addr != _node.addr || len != _node.len || prev != _node.prev || - next != _node.next; +bool SLAB::chunk_t::operator!=(const chunk_t& _node) const { + return addr != _node.addr || len != _node.len || prev != _node.prev + || next != _node.next; } -SLAB::chunk_t &SLAB::chunk_t::operator[](size_t _idx) const { +SLAB::chunk_t& SLAB::chunk_t::operator[](size_t _idx) const { // 判断越界 assert(_idx < size()); - const chunk_t *res = nullptr; + const chunk_t* res = nullptr; // 找到头节点 - const chunk_t *tmp = this; + const chunk_t* tmp = this; while (tmp->next != this) { if (tmp->addr == HEAD && tmp->len == HEAD) { res = tmp; @@ -72,11 +72,11 @@ SLAB::chunk_t &SLAB::chunk_t::operator[](size_t _idx) const { } // res 必不为空 assert(res != nullptr); - return *(const_cast(res)); + return *(const_cast(res)); } // 由于是循环队列,相当于在头节点前面插入 -void SLAB::chunk_t::push_back(chunk_t *_new_node) { +void SLAB::chunk_t::push_back(chunk_t* _new_node) { _new_node->next = this; _new_node->prev = prev; prev->next = _new_node; @@ -84,36 +84,53 @@ void SLAB::chunk_t::push_back(chunk_t *_new_node) { return; } -void SLAB::slab_cache_t::move(chunk_t &_list, chunk_t *_node) { +void SLAB::slab_cache_t::move(chunk_t& _list, chunk_t* _node) { // 从当前链表中删除 _node->prev->next = _node->next; _node->next->prev = _node->prev; // 重置指针 - _node->prev = _node; - _node->next = _node; + _node->prev = _node; + _node->next = _node; // 插入新链表 _list.push_back(_node); return; } -SLAB::chunk_t *SLAB::slab_cache_t::alloc_pmm(size_t _len) { +SLAB::chunk_t* SLAB::slab_cache_t::alloc_pmm(size_t _len) { // 计算页数 size_t pages = _len / COMMON::PAGE_SIZE; if (_len % COMMON::PAGE_SIZE != 0) { pages += 1; } // 申请 - chunk_t *new_node = (chunk_t *)PMM::get_instance().alloc_pages(pages); + chunk_t* new_node = nullptr; + if (is_kernel_space == true) { + new_node = (chunk_t*)PMM::get_instance().alloc_pages_kernel(pages); + } + else { + new_node = (chunk_t*)PMM::get_instance().alloc_pages(pages); + } // 如果没有映射则进行映射 uintptr_t tmp = 0; for (size_t i = 0; i < pages; i++) { // 地址=初始地址+页数偏移 - tmp = (uintptr_t)((uint8_t *)new_node + i * COMMON::PAGE_SIZE); - if (VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), tmp, - 0) == false) { - VMM::get_instance().mmap(VMM::get_instance().get_pgd(), - (uintptr_t)new_node, (uintptr_t)new_node, - VMM_PAGE_READABLE | VMM_PAGE_WRITABLE); + tmp = (uintptr_t)((uint8_t*)new_node + i * COMMON::PAGE_SIZE); + if ((VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), tmp, 0) + == false) + || (is_kernel_space)) { + if (is_kernel_space == true) { + VMM::get_instance().mmap(VMM::get_instance().get_pgd(), + (uintptr_t)new_node, + (uintptr_t)new_node, + VMM_PAGE_READABLE | VMM_PAGE_WRITABLE); + } + else { + VMM::get_instance().mmap(VMM::get_instance().get_pgd(), + (uintptr_t)new_node, + (uintptr_t)new_node, + VMM_PAGE_READABLE | VMM_PAGE_WRITABLE + | VMM_PAGE_USER); + } } // 已经映射的情况是不应该出现的 else { @@ -126,7 +143,7 @@ SLAB::chunk_t *SLAB::slab_cache_t::alloc_pmm(size_t _len) { // 自身的地址 new_node->addr = (uintptr_t)new_node; // 长度需要减去 chunk_t 的长度 - new_node->len = (pages * COMMON::PAGE_SIZE) - CHUNK_SIZE; + new_node->len = (pages * COMMON::PAGE_SIZE) - CHUNK_SIZE; // 链表指针 new_node->prev = new_node; new_node->next = new_node; @@ -137,19 +154,19 @@ SLAB::chunk_t *SLAB::slab_cache_t::alloc_pmm(size_t _len) { } void SLAB::slab_cache_t::free_pmm(void) { - size_t pages = 0; + size_t pages = 0; // 遍历 free 链表 - chunk_t *tmp = free.next; + chunk_t* tmp = free.next; while (tmp != &free) { pages = (tmp->len + CHUNK_SIZE) / COMMON::PAGE_SIZE; // 必须是整数个页 assert(((tmp->len + CHUNK_SIZE) % COMMON::PAGE_SIZE) == 0); PMM::get_instance().free_pages(tmp->addr, pages); // 删除节点 - tmp->prev->next = tmp->next; - tmp->next->prev = tmp->prev; + tmp->prev->next = tmp->next; + tmp->next->prev = tmp->prev; // 取消映射后无法访问 tmp,所以提前保存 - auto tmp_next = tmp->next; + auto tmp_next = tmp->next; // 取消映射 // 因为每次只能取消映射 1 页,所以需要循环 uintptr_t tmp_addr = 0; @@ -165,11 +182,11 @@ void SLAB::slab_cache_t::free_pmm(void) { return; } -void SLAB::slab_cache_t::split(chunk_t *_node, size_t _len) { +void SLAB::slab_cache_t::split(chunk_t* _node, size_t _len) { // 记录原大小 size_t old_len = _node->len; // 更新旧节点 - _node->len = _len; + _node->len = _len; // 旧节点移动到 full move(full, _node); // 原长度大于要分配的长度+新 chunk 长度 @@ -177,14 +194,14 @@ void SLAB::slab_cache_t::split(chunk_t *_node, size_t _len) { if (old_len > _len + CHUNK_SIZE) { // 处理新节点 // 新节点地址为原本地址+chunk大小+要分配出去的长度 - chunk_t *new_node = (chunk_t *)(_node->addr + CHUNK_SIZE + _len); + chunk_t* new_node = (chunk_t*)(_node->addr + CHUNK_SIZE + _len); new_node->addr = (uintptr_t)new_node; // 剩余长度为原本的长度减去要分配给 _node 的长度,减去新节点的 chunk // 大小 - new_node->len = old_len - _len - CHUNK_SIZE; + new_node->len = old_len - _len - CHUNK_SIZE; // 手动初始化节点 - new_node->prev = new_node; - new_node->next = new_node; + new_node->prev = new_node; + new_node->next = new_node; // 判断剩余空间是否可以容纳至少一个节点,即大于等于 len+CHUNK_SIZE // 如果大于等于则建立新的节点,小于的话不用新建 // 这里只有 len 是因为 chunk 的大小并不包括在 chunk->len @@ -206,8 +223,8 @@ void SLAB::slab_cache_t::merge(void) { // 合并的条件 // node1->addr+CHUNK_SIZE+node1->len==node2->addr // 暴力遍历 - chunk_t *chunk = part.next; - chunk_t *tmp = chunk->next; + chunk_t* chunk = part.next; + chunk_t* tmp = chunk->next; // 外层循环 while (chunk != &part) { // 内层循环 @@ -216,12 +233,12 @@ void SLAB::slab_cache_t::merge(void) { if (chunk->addr + CHUNK_SIZE + chunk->len == tmp->addr) { // 进行合并 // 加上 tmp 的 chunk 长度 - chunk->len += CHUNK_SIZE; + chunk->len += CHUNK_SIZE; // 加上 tmp 的 len 长度 - chunk->len += tmp->len; + chunk->len += tmp->len; // 删除 tmp - tmp->prev->next = tmp->next; - tmp->next->prev = tmp->prev; + tmp->prev->next = tmp->next; + tmp->next->prev = tmp->prev; break; } tmp = tmp->next; @@ -250,11 +267,11 @@ void SLAB::slab_cache_t::merge(void) { return; } -SLAB::chunk_t *SLAB::slab_cache_t::find(chunk_t &_which, size_t _len, - bool _alloc) { - chunk_t *res = nullptr; +SLAB::chunk_t* +SLAB::slab_cache_t::find(chunk_t& _which, size_t _len, bool _alloc) { + chunk_t* res = nullptr; // 在 _which 中查找,直接遍历即可 - chunk_t *tmp = _which.next; + chunk_t* tmp = _which.next; while (tmp != &_which) { // 如果 tmp 节点的长度大于等于 _len if (tmp->len >= _len) { @@ -279,16 +296,16 @@ SLAB::chunk_t *SLAB::slab_cache_t::find(chunk_t &_which, size_t _len, return res; } -SLAB::chunk_t *SLAB::slab_cache_t::find(size_t _len) { - chunk_t *chunk = nullptr; +SLAB::chunk_t* SLAB::slab_cache_t::find(size_t _len) { + chunk_t* chunk = nullptr; // 在 part 里找,如果没有找到允许申请新的空间 - chunk = find(part, _len, true); + chunk = find(part, _len, true); // 如果到这里 chunk 还为 nullptr 说明空间不够了 assert(chunk != nullptr); return chunk; } -void SLAB::slab_cache_t::remove(chunk_t *_node) { +void SLAB::slab_cache_t::remove(chunk_t* _node) { // 将 _node 移动到 part 即可 move(part, _node); // merge 会处理节点合并的情况 @@ -297,9 +314,9 @@ void SLAB::slab_cache_t::remove(chunk_t *_node) { } size_t SLAB::get_idx(size_t _len) const { - size_t res = 0; + size_t res = 0; // _len 向上取整 - _len += _len - 1; + _len += _len - 1; while (1) { // 每次右移一位 _len = _len >> 1; @@ -309,7 +326,6 @@ size_t SLAB::get_idx(size_t _len) const { res = 0; } else { - res -= SHIFT; } break; @@ -319,11 +335,12 @@ size_t SLAB::get_idx(size_t _len) const { return res; } -SLAB::SLAB(const char *_name, uintptr_t _addr, size_t _len) - : ALLOCATOR(_name, _addr, _len) { +SLAB::SLAB(const char* _name, uintptr_t _addr, size_t _len, bool _is_kernel) + : ALLOCATOR(_name, _addr, _len), is_kernel_space(_is_kernel) { // 初始化 slab_cache for (size_t i = LEN256; i < LEN65536; i++) { - slab_cache[i].len = MIN << i; + slab_cache[i].len = MIN << i; + slab_cache[i].is_kernel_space = _is_kernel; } info("%s: 0x%p(0x%p bytes) init.\n", name, allocator_start_addr, allocator_length); @@ -342,11 +359,11 @@ uintptr_t SLAB::alloc(size_t _len) { // 大小不能超过 65536B if (_len > 0 && _len <= MIN << LEN65536) { // _len 按照 8bytes 对齐 - _len = COMMON::ALIGN(_len, 8); + _len = COMMON::ALIGN(_len, 8); // 根据大小确定 slab_cache 索引 - auto idx = get_idx(_len); + auto idx = get_idx(_len); // 寻找合适的 slab 节点 - chunk_t *chunk = slab_cache[idx].find(_len); + chunk_t* chunk = slab_cache[idx].find(_len); // 不为空的话计算地址 if (chunk != nullptr) { assert((uintptr_t)chunk == chunk->addr); @@ -357,7 +374,7 @@ uintptr_t SLAB::alloc(size_t _len) { #ifdef DEBUG info("slab alloc\n"); std::cout << slab_cache[idx]; -#undef DEBUG +# undef DEBUG #endif } // 更新统计数据 @@ -378,7 +395,7 @@ void SLAB::free(uintptr_t _addr, size_t) { } // 要释放一个 chunk // 1. 计算 chunk 地址 - chunk_t *chunk = (chunk_t *)(_addr - CHUNK_SIZE); + chunk_t* chunk = (chunk_t*)(_addr - CHUNK_SIZE); assert((uintptr_t)chunk == chunk->addr); // 2. 计算所属 slab_cache 索引 auto a = chunk->len; @@ -390,7 +407,7 @@ void SLAB::free(uintptr_t _addr, size_t) { #ifdef DEBUG info("slab free\n"); std::cout << slab_cache[idx]; -#undef DEBUG +# undef DEBUG #endif // 更新统计数据 allocator_used_count -= a; diff --git a/src/kernel/test.cpp b/src/kernel/test.cpp index 05eaf356f..0cfae3ae8 100644 --- a/src/kernel/test.cpp +++ b/src/kernel/test.cpp @@ -1,26 +1,36 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// test.cpp for Simple-XX/SimpleKernel. +/** + * @file test.cpp + * @brief 测试 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ +#include "cassert" #include "common.h" -#include "stdio.h" -#include "iostream" -#include "assert.h" -#include "pmm.h" -#include "vmm.h" +#include "cstdio" +#include "cstdlib" #include "heap.h" #include "kernel.h" +#include "pmm.h" +#include "vmm.h" int32_t test_pmm(void) { // 保存现有 pmm 空闲页数量 size_t free_pages = PMM::get_instance().get_free_pages_count(); // 计算内核实际占用页数 - auto kernel_pages = - (COMMON::ALIGN(COMMON::KERNEL_END_ADDR, COMMON::PAGE_SIZE) - - COMMON::ALIGN(COMMON::KERNEL_START_ADDR, COMMON::PAGE_SIZE)) / - COMMON::PAGE_SIZE; + auto kernel_pages + = (COMMON::ALIGN(COMMON::KERNEL_END_ADDR, COMMON::PAGE_SIZE) + - COMMON::ALIGN(COMMON::KERNEL_START_ADDR, COMMON::PAGE_SIZE)) + / COMMON::PAGE_SIZE; // 再加上启动信息使用的页,一般为一页 kernel_pages++; // TODO: 替换宏 @@ -29,9 +39,9 @@ int32_t test_pmm(void) { kernel_pages++; #endif // 空闲页数应该等于物理内存大小-内核使用 - assert(free_pages == - (PMM::get_instance().get_pmm_length() / COMMON::PAGE_SIZE) - - kernel_pages); + assert(free_pages + == (PMM::get_instance().get_pmm_length() / COMMON::PAGE_SIZE) + - kernel_pages); // 获取已使用页数 size_t used_pages = PMM::get_instance().get_used_pages_count(); // 已使用页数应该等于内核使用页数 @@ -59,60 +69,100 @@ int32_t test_pmm(void) { PMM::get_instance().free_pages(addr4, 100); // 现在内存使用情况应该与此函数开始时相同 assert(PMM::get_instance().get_free_pages_count() == free_pages); + // 下面测试内核空间物理内存分配 + // 已使用页数应该等于内核使用页数 + assert(used_pages == kernel_pages); + // 分配 + addr1 = PMM::get_instance().alloc_pages_kernel(2); + // 已使用应该会更新 + assert(PMM::get_instance().get_used_pages_count() == 2 + kernel_pages); + // 同上 + addr2 = PMM::get_instance().alloc_pages_kernel(3); + assert(PMM::get_instance().get_used_pages_count() == 5 + kernel_pages); + // 同上 + addr3 = PMM::get_instance().alloc_pages_kernel(100); + assert(PMM::get_instance().get_used_pages_count() == 105 + kernel_pages); + // 同上 + addr4 = PMM::get_instance().alloc_pages_kernel(100); + assert(PMM::get_instance().get_used_pages_count() == 205 + kernel_pages); + // 分配超过限度的内存,应该返回 nullptr + addr5 = PMM::get_instance().alloc_pages_kernel(0xFFFFFFFF); + assert(addr5 == 0); + // 全部释放 + PMM::get_instance().free_pages(addr1, 2); + PMM::get_instance().free_pages(addr2, 3); + PMM::get_instance().free_pages(addr3, 100); + PMM::get_instance().free_pages(addr4, 100); + // 现在内存使用情况应该与此函数开始时相同 + assert(PMM::get_instance().get_free_pages_count() == free_pages); info("pmm test done.\n"); return 0; } +/// @note riscv 内核模式下无法测试 VMM_PAGE_USER,默认状态下 S/U +/// 模式的页无法互相访问 +/// @see +/// https://five-embeddev.com/riscv-isa-manual/latest/supervisor.html#sec:translation int32_t test_vmm(void) { uintptr_t addr = 0; // 首先确认内核空间被映射了 assert(VMM::get_instance().get_pgd() != nullptr); assert(VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), (COMMON::KERNEL_START_ADDR + 0x1000), - &addr) == 1); + &addr) + == 1); assert(addr == COMMON::KERNEL_START_ADDR + 0x1000); addr = 0; assert(VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), - COMMON::KERNEL_START_ADDR + - VMM_KERNEL_SPACE_SIZE - 1, - &addr) == 1); - assert(addr == ((COMMON::KERNEL_START_ADDR + VMM_KERNEL_SPACE_SIZE - 1) & - COMMON::PAGE_MASK)); + COMMON::KERNEL_START_ADDR + + VMM_KERNEL_SPACE_SIZE - 1, + &addr) + == 1); + assert(addr + == ((COMMON::KERNEL_START_ADDR + VMM_KERNEL_SPACE_SIZE - 1) + & COMMON::PAGE_MASK)); addr = 0; assert(VMM::get_instance().get_mmap( - VMM::get_instance().get_pgd(), - (COMMON::ALIGN(COMMON::KERNEL_START_ADDR, 4 * COMMON::KB) + - VMM_KERNEL_SPACE_SIZE), - &addr) == 0); + VMM::get_instance().get_pgd(), + (COMMON::ALIGN(COMMON::KERNEL_START_ADDR, 4 * COMMON::KB) + + VMM_KERNEL_SPACE_SIZE), + &addr) + == 0); assert(addr == 0); addr = 0; assert(VMM::get_instance().get_mmap( - VMM::get_instance().get_pgd(), - (COMMON::ALIGN(COMMON::KERNEL_START_ADDR, 4 * COMMON::KB) + - VMM_KERNEL_SPACE_SIZE + 0x1024), - 0) == 0); + VMM::get_instance().get_pgd(), + (COMMON::ALIGN(COMMON::KERNEL_START_ADDR, 4 * COMMON::KB) + + VMM_KERNEL_SPACE_SIZE + 0x1024), + 0) + == 0); // 测试映射与取消映射 - addr = 0; + addr = 0; // 准备映射的虚拟地址 3GB 处 uintptr_t va = 0xC0000000; - // 准备映射的物理地址 0.75GB 处 - uintptr_t pa = 0x30000000; + // 分配要映射的物理地址 + uintptr_t pa = PMM::get_instance().alloc_page_kernel(); // 确定一块未映射的内存 assert(VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), va, - nullptr) == 0); + nullptr) + == 0); // 映射 VMM::get_instance().mmap(VMM::get_instance().get_pgd(), va, pa, VMM_PAGE_READABLE | VMM_PAGE_WRITABLE); assert(VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), va, - &addr) == 1); + &addr) + == 1); assert(addr == pa); // 写测试 - *(uintptr_t *)va = 0xCD; - //取消映射 + *(uintptr_t*)va = 0xCD; + // 取消映射 VMM::get_instance().unmmap(VMM::get_instance().get_pgd(), va); assert(VMM::get_instance().get_mmap(VMM::get_instance().get_pgd(), va, - &addr) == 0); + &addr) + == 0); assert(addr == 0); + // 回收物理地址 + PMM::get_instance().free_page(pa); info("vmm test done.\n"); return 0; } @@ -121,41 +171,57 @@ int32_t test_vmm(void) { int test_heap(void) { // 根据字长不同 CHUNK_SIZE 是不一样的 size_t chunk_size = 0; - if (sizeof(void *) == 4) { + if (sizeof(void*) == 4) { chunk_size = 0x10; } - else if (sizeof(void *) == 8) { + else if (sizeof(void*) == 8) { chunk_size = 0x20; } - void *addr1 = nullptr; - void *addr2 = nullptr; - void *addr3 = nullptr; - void *addr4 = nullptr; + void* addr1 = nullptr; + void* addr2 = nullptr; + void* addr3 = nullptr; + void* addr4 = nullptr; // 申请超过最大允许的内存 65536B - addr1 = HEAP::get_instance().malloc(0x10001); + addr1 = kmalloc(0x10001); // 应该返回 nullptr assert(addr1 == nullptr); // 申请小块内存 - addr2 = HEAP::get_instance().malloc(0x1); + addr2 = kmalloc(0x1); assert(addr2 != nullptr); // 第一块被申请的内存,减去 chunk 大小后应该是 4k 对齐的 - assert(((uintptr_t)((uint8_t *)addr2 - chunk_size) & 0xFFF) == 0x0); + assert(((uintptr_t)((uint8_t*)addr2 - chunk_size) & 0xFFF) == 0x0); // 在 LEN512 申请新的内存 - addr3 = HEAP::get_instance().malloc(0x200); + addr3 = kmalloc(0x200); assert(addr3 != nullptr); // 第一块被申请的内存,减去 chunk 大小后应该是 4k 对齐的 - assert(((uintptr_t)((uint8_t *)addr3 - chunk_size) & 0xFFF) == 0x0); + assert(((uintptr_t)((uint8_t*)addr3 - chunk_size) & 0xFFF) == 0x0); // 加上 chunk 大小长度刚好是 LEN256 - addr4 = HEAP::get_instance().malloc(0x80); + addr4 = kmalloc(0x80); assert(addr4 != nullptr); // LEN256 区域第二块被申请的内存,地址可以计算出来 // 前一个块的地址+chunk 长度+数据长度+对齐长度 - assert(addr4 == (uint8_t *)addr2 + chunk_size + 0x1 + 0x7); + assert(addr4 == (uint8_t*)addr2 + chunk_size + 0x1 + 0x7); + /// @bug 这里释放会同时 unmmap,导致后面的分支出现 pg // 全部释放 - HEAP::get_instance().free(addr1); - HEAP::get_instance().free(addr2); - HEAP::get_instance().free(addr3); - HEAP::get_instance().free(addr4); + // kfree(addr1); + // kfree(addr2); + // kfree(addr3); + // kfree(addr4); info("heap test done.\n"); return 0; } + +// TODO: 更多测试 +int test_intr(void) { + // 触发 pg 中断 + uintptr_t* addr = (uintptr_t*)0xC0000000; + int tmp = 0x666; + tmp = *addr; + assert(tmp == 0); + *addr = 0x233; + tmp = *addr; + assert(tmp == 0x233); + *addr = 0x0; + info("intr test done.\n"); + return 0; +} diff --git a/src/kernel/vmm.cpp b/src/kernel/vmm.cpp index 77b4f904c..00dfe6156 100644 --- a/src/kernel/vmm.cpp +++ b/src/kernel/vmm.cpp @@ -14,27 +14,27 @@ * */ -#include "stdint.h" -#include "string.h" -#include "stdio.h" -#include "assert.h" +#include "cassert" #include "cpu.hpp" +#include "cstdint" +#include "cstdio" +#include "cstring" #if defined(__i386__) || defined(__x86_64__) -#include "gdt.h" +# include "gdt.h" #endif #include "pmm.h" #include "vmm.h" // 在 _pgd 中查找 _va 对应的页表项 // 如果未找到,_alloc 为真时会进行分配 -pte_t *VMM::find(const pt_t _pgd, uintptr_t _va, bool _alloc) { +pte_t* VMM::find(const pt_t _pgd, uintptr_t _va, bool _alloc) { pt_t pgd = _pgd; // sv39 共有三级页表,一级一级查找 // -1 是因为最后一级是具体的某一页,在函数最后直接返回 for (size_t level = VMM_PT_LEVEL - 1; level > 0; level--) { // 每次循环会找到 _va 的第 level 级页表 pgd // 相当于 pgd_level[VPN_level],这样相当于得到了第 level 级页表的地址 - pte_t *pte = (pte_t *)&pgd[PX(level, _va)]; + pte_t* pte = (pte_t*)&pgd[PX(level, _va)]; // 解引用 pte,如果有效,获取 level+1 级页表, if ((*pte & VMM_PAGE_VALID) == 1) { // pgd 指向下一级页表 @@ -70,7 +70,7 @@ pte_t *VMM::find(const pt_t _pgd, uintptr_t _va, bool _alloc) { return &pgd[PX(0, _va)]; } -VMM &VMM::get_instance(void) { +VMM& VMM::get_instance(void) { /// 定义全局 VMM 对象 static VMM vmm; return vmm; @@ -112,27 +112,28 @@ void VMM::set_pgd(const pt_t _pgd) { } void VMM::mmap(const pt_t _pgd, uintptr_t _va, uintptr_t _pa, uint32_t _flag) { - pte_t *pte = find(_pgd, _va, true); + pte_t* pte = find(_pgd, _va, true); // 一般情况下不应该为空 assert(pte != nullptr); // 已经映射过了 且 flag 没有变化 - if (((*pte & VMM_PAGE_VALID) == VMM_PAGE_VALID) && - ((*pte & _flag) == _flag)) { + if (((*pte & VMM_PAGE_VALID) == VMM_PAGE_VALID) + && ((*pte & ((1 << VMM_PTE_PROP_BITS) - 1)) == _flag)) { warn("remap.\n"); } // 没有映射,或更改了 flag else { // 那么设置 *pte // pte 解引用后的值是页表项 - *pte = PA2PTE(_pa) | _flag | VMM_PAGE_VALID; + *pte = PA2PTE(_pa) | _flag | (*pte & ((1 << VMM_PTE_PROP_BITS) - 1)) + | VMM_PAGE_VALID; // 刷新缓存 - CPU::VMM_FLUSH((uintptr_t)_va); + CPU::VMM_FLUSH(0); } return; } void VMM::unmmap(const pt_t _pgd, uintptr_t _va) { - pte_t *pte = find(_pgd, _va, false); + pte_t* pte = find(_pgd, _va, false); // 找到页表项 // 未找到 if (pte == nullptr) { @@ -146,13 +147,13 @@ void VMM::unmmap(const pt_t _pgd, uintptr_t _va) { // 置零 *pte = 0x00; // 刷新缓存 - CPU::VMM_FLUSH((uintptr_t)_va); + CPU::VMM_FLUSH(0); // TODO: 如果一页表都被 unmap,释放占用的物理内存 return; } -bool VMM::get_mmap(const pt_t _pgd, uintptr_t _va, const void *_pa) { - pte_t *pte = find(_pgd, _va, false); +bool VMM::get_mmap(const pt_t _pgd, uintptr_t _va, const void* _pa) { + pte_t* pte = find(_pgd, _va, false); bool res = false; // pte 不为空且有效,说明映射了 if ((pte != nullptr) && ((*pte & VMM_PAGE_VALID) == 1)) { @@ -160,7 +161,7 @@ bool VMM::get_mmap(const pt_t _pgd, uintptr_t _va, const void *_pa) { if (_pa != nullptr) { // 设置 _pa // 将页表项转换为物理地址 - *(uintptr_t *)_pa = PTE2PA(*pte); + *(uintptr_t*)_pa = PTE2PA(*pte); } // 返回 true res = true; @@ -170,7 +171,7 @@ bool VMM::get_mmap(const pt_t _pgd, uintptr_t _va, const void *_pa) { // 如果 _pa 不为空 if (_pa != nullptr) { // 设置 _pa - *(uintptr_t *)_pa = (uintptr_t) nullptr; + *(uintptr_t*)_pa = (uintptr_t) nullptr; } } return res; diff --git a/src/libc/CMakeLists.txt b/src/libc/CMakeLists.txt index 2030abe50..4e9453e64 100644 --- a/src/libc/CMakeLists.txt +++ b/src/libc/CMakeLists.txt @@ -1,5 +1,6 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # CMakeLists.txt for Simple-XX/SimpleKernel. diff --git a/src/libc/include/assert.h b/src/libc/include/assert.h index c09fa38bb..f72e7435e 100644 --- a/src/libc/include/assert.h +++ b/src/libc/include/assert.h @@ -1,16 +1,36 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// assert.h for Simple-XX/SimpleKernel. +/** + * @file assert.h + * @brief assert 实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://wiki.osdev.org/Raspberry_Pi_Bare_Bones + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _ASSERT_H_ -#define _ASSERT_H_ +#ifndef SIMPLEKERNEL_ASSERT_H +#define SIMPLEKERNEL_ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif #include "stdio.h" -#define assert(e) ((void)((e) ? ((void)0) : __assert(#e, __FILE__, __LINE__))) -#define __assert(e, file, line) \ - ((void)err("%s:%d: failed assertion `%s'\n", file, line, e)) +#define assert(_e) \ + ((void)((_e) ? ((void)0) : __assert(#_e, __FILE__, __LINE__))) +#define __assert(_e, _file, _line) \ + ((void)err("%s:%d: failed assertion `%s'\n", _file, _line, _e)) + +#ifdef __cplusplus +} +#endif -#endif /* _ASSERT_H_ */ +#endif /* SIMPLEKERNEL_ASSERT_H */ diff --git a/src/libc/include/ctype.h b/src/libc/include/ctype.h index b1c94e324..269611839 100644 --- a/src/libc/include/ctype.h +++ b/src/libc/include/ctype.h @@ -1,23 +1,33 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// ctype.h for Simple-XX/SimpleKernel. +/** + * @file ctype.h + * @brief ctype 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _CTYPE_H_ -#define _CTYPE_H_ +#ifndef SIMPLEKERNEL_CTYPE_H +#define SIMPLEKERNEL_CTYPE_H #ifdef __cplusplus extern "C" { #endif -#define isupper(c) (c >= 'A' && c <= 'Z') -#define isalpha(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) -#define isspace(c) (c == ' ' || c == '\t' || c == '\n' || c == '\12') -#define isdigit(c) (c >= '0' && c <= '9') +#define isupper(_c) (_c >= 'A' && _c <= 'Z') +#define isalpha(_c) ((_c >= 'A' && _c <= 'Z') || (_c >= 'a' && _c <= 'z')) +#define isspace(_c) (_c == ' ' || _c == '\t' || _c == '\n' || _c == '\12') +#define isdigit(_c) (_c >= '0' && _c <= '9') #ifdef __cplusplus } #endif -#endif /* _CTYPE_H_ */ +#endif /* SIMPLEKERNEL_CTYPE_H */ diff --git a/src/libc/include/endian.h b/src/libc/include/endian.h index 335fc0299..27b5b7c7c 100644 --- a/src/libc/include/endian.h +++ b/src/libc/include/endian.h @@ -1,11 +1,21 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// endian.h for Simple-XX/SimpleKernel. - -#ifndef _ENDIAN_H_ -#define _ENDIAN_H_ +/** + * @file endian.h + * @brief endian 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_ENDIAN_H +#define SIMPLEKERNEL_ENDIAN_H #ifdef __cplusplus extern "C" { @@ -17,87 +27,89 @@ extern "C" { static union { char c[4]; unsigned long mylong; -} endian_test __attribute__((unused)) = {{'l', '?', '?', 'b'}}; +} endian_test __attribute__((unused)) = { + {'l', '?', '?', 'b'} +}; // 'l' 为小端,'b' 为大端 -#define ENDIANNESS ((char)endian_test.mylong) +#define ENDIANNESS ((char)endian_test.mylong) #define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#define __PDP_ENDIAN 3412 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 #if defined(__riscv) || defined(__i386__) || defined(__x86_64__) -#define __BYTE_ORDER __LITTLE_ENDIAN +# define __BYTE_ORDER __LITTLE_ENDIAN #else -#define __BYTE_ORDER __BIG_ENDIAN +# define __BYTE_ORDER __BIG_ENDIAN #endif -#define BIG_ENDIAN __BIG_ENDIAN +#define BIG_ENDIAN __BIG_ENDIAN #define LITTLE_ENDIAN __LITTLE_ENDIAN -#define PDP_ENDIAN __PDP_ENDIAN -#define BYTE_ORDER __BYTE_ORDER +#define PDP_ENDIAN __PDP_ENDIAN +#define BYTE_ORDER __BYTE_ORDER -static inline uint16_t __bswap16(uint16_t __x) { +inline static uint16_t __bswap16(uint16_t __x) { return (__x << 8) | (__x >> 8); } -static inline uint32_t __bswap32(uint32_t __x) { - return (__x >> 24) | (__x >> 8 & 0xff00) | (__x << 8 & 0xff0000) | - (__x << 24); +inline static uint32_t __bswap32(uint32_t __x) { + return (__x >> 24) | (__x >> 8 & 0xff00) | (__x << 8 & 0xff0000) + | (__x << 24); } -static inline uint64_t __bswap64(uint64_t __x) { +inline static uint64_t __bswap64(uint64_t __x) { return (__bswap32(__x) + (0ULL << 32)) | __bswap32(__x >> 32); } #if __BYTE_ORDER == __LITTLE_ENDIAN -#define htobe16(x) __bswap16(x) -#define be16toh(x) __bswap16(x) -#define htobe32(x) __bswap32(x) -#define be32toh(x) __bswap32(x) -#define htobe64(x) __bswap64(x) -#define be64toh(x) __bswap64(x) -#define htole16(x) (uint16_t)(x) -#define le16toh(x) (uint16_t)(x) -#define htole32(x) (uint32_t)(x) -#define le32toh(x) (uint32_t)(x) -#define htole64(x) (uint64_t)(x) -#define le64toh(x) (uint64_t)(x) +# define htobe16(x) __bswap16(x) +# define be16toh(x) __bswap16(x) +# define htobe32(x) __bswap32(x) +# define be32toh(x) __bswap32(x) +# define htobe64(x) __bswap64(x) +# define be64toh(x) __bswap64(x) +# define htole16(x) (uint16_t)(x) +# define le16toh(x) (uint16_t)(x) +# define htole32(x) (uint32_t)(x) +# define le32toh(x) (uint32_t)(x) +# define htole64(x) (uint64_t)(x) +# define le64toh(x) (uint64_t)(x) #else -#define htobe16(x) (uint16_t)(x) -#define be16toh(x) (uint16_t)(x) -#define htobe32(x) (uint32_t)(x) -#define be32toh(x) (uint32_t)(x) -#define htobe64(x) (uint64_t)(x) -#define be64toh(x) (uint64_t)(x) -#define htole16(x) __bswap16(x) -#define le16toh(x) __bswap16(x) -#define htole32(x) __bswap32(x) -#define le32toh(x) __bswap32(x) -#define htole64(x) __bswap64(x) -#define le64toh(x) __bswap64(x) +# define htobe16(x) (uint16_t)(x) +# define be16toh(x) (uint16_t)(x) +# define htobe32(x) (uint32_t)(x) +# define be32toh(x) (uint32_t)(x) +# define htobe64(x) (uint64_t)(x) +# define be64toh(x) (uint64_t)(x) +# define htole16(x) __bswap16(x) +# define le16toh(x) __bswap16(x) +# define htole32(x) __bswap32(x) +# define le32toh(x) __bswap32(x) +# define htole64(x) __bswap64(x) +# define le64toh(x) __bswap64(x) #endif #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define betoh16(x) __bswap16(x) -#define betoh32(x) __bswap32(x) -#define betoh64(x) __bswap64(x) -#define letoh16(x) (uint16_t)(x) -#define letoh32(x) (uint32_t)(x) -#define letoh64(x) (uint64_t)(x) -#else -#define betoh16(x) (uint16_t)(x) -#define betoh32(x) (uint32_t)(x) -#define betoh64(x) (uint64_t)(x) -#define letoh16(x) __bswap16(x) -#define letoh32(x) __bswap32(x) -#define letoh64(x) __bswap64(x) -#endif +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define betoh16(x) __bswap16(x) +# define betoh32(x) __bswap32(x) +# define betoh64(x) __bswap64(x) +# define letoh16(x) (uint16_t)(x) +# define letoh32(x) (uint32_t)(x) +# define letoh64(x) (uint64_t)(x) +# else +# define betoh16(x) (uint16_t)(x) +# define betoh32(x) (uint32_t)(x) +# define betoh64(x) (uint64_t)(x) +# define letoh16(x) __bswap16(x) +# define letoh32(x) __bswap32(x) +# define letoh64(x) __bswap64(x) +# endif #endif #ifdef __cplusplus } #endif -#endif /* _ENDIAN_H_ */ +#endif /* SIMPLEKERNEL_ENDIAN_H */ diff --git a/src/libc/include/float.h b/src/libc/include/float.h index 4362fcabc..3b02c7816 100644 --- a/src/libc/include/float.h +++ b/src/libc/include/float.h @@ -1,11 +1,21 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// float.h for Simple-XX/SimpleKernel. +/** + * @file float.h + * @brief float 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _FLOAT_H_ -#define _FLOAT_H_ +#ifndef SIMPLEKERNEL_FLOAT_H +#define SIMPLEKERNEL_FLOAT_H #ifdef __cplusplus extern "C" { @@ -17,4 +27,4 @@ extern "C" { } #endif -#endif /* _FLOAT_H_ */ +#endif /* SIMPLEKERNEL_FLOAT_H */ diff --git a/src/libc/include/limits.h b/src/libc/include/limits.h index 2659c2590..a4c30cd38 100644 --- a/src/libc/include/limits.h +++ b/src/libc/include/limits.h @@ -1,53 +1,63 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// limits.h for Simple-XX/SimpleKernel. - -#ifndef _LIMITS_H_ -#define _LIMITS_H_ +/** + * @file limits.h + * @brief limits 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_LIMITS_H +#define SIMPLEKERNEL_LIMITS_H #ifdef __cplusplus extern "C" { #endif // int8_t -#define SCHAR_MIN (-128) -#define SCHAR_MAX (127) +#define SCHAR_MIN (-128) +#define SCHAR_MAX (127) // uint8_t -#define UCHAR_MAX (0xFF) +#define UCHAR_MAX (0xFF) // int16_t -#define SHRT_MIN (-32768) -#define SHRT_MAX (32767) +#define SHRT_MIN (-32768) +#define SHRT_MAX (32767) // uint16_t -#define USHRT_MAX (0xFFFF) +#define USHRT_MAX (0xFFFF) // 4字节 int和unsigned int类型 // int32_t -#define INT_MIN (-2147483647 - 1) -#define INT_MAX (2147483647) +#define INT_MIN (-2147483647 - 1) +#define INT_MAX (2147483647) // uint32_t -#define UINT_MAX (0xFFFFFFFF) +#define UINT_MAX (0xFFFFFFFF) // 32bit 与 64bit 不同 // 0x7FFFFFFF -#define LONG_MAX ((long)(ULONG_MAX >> 1)) +#define LONG_MAX ((long)(ULONG_MAX >> 1)) // 0x80000000 -#define LONG_MIN ((long)(~LONG_MAX)) +#define LONG_MIN ((long)(~LONG_MAX)) // 0xFFFFFFFF -#define ULONG_MAX ((unsigned long)(~0L)) +#define ULONG_MAX ((unsigned long)(~0L)) // 8字节 long long int和 unsigned long long int类型 // 0xFFFFFFFFFFFFFFFF #define ULLONG_MAX (~(unsigned long long)0) // 0x7FFFFFFFFFFFFFFF -#define LLONG_MAX ((long long)(ULLONG_MAX >> 1)) +#define LLONG_MAX ((long long)(ULLONG_MAX >> 1)) // 0x8000000000000000 -#define LLONG_MIN (~LLONG_MAX) +#define LLONG_MIN (~LLONG_MAX) #ifdef __cplusplus } #endif -#endif /* _LIMITS_H_ */ +#endif /* SIMPLEKERNEL_LIMITS_H */ diff --git a/src/libc/include/math.h b/src/libc/include/math.h index 3bc44c05b..33d540b48 100644 --- a/src/libc/include/math.h +++ b/src/libc/include/math.h @@ -1,11 +1,22 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on libgcc -// math.h for Simple-XX/SimpleKernel. +/** + * @file math.h + * @brief math 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on libgcc + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _MATH_H_ -#define _MATH_H_ +#ifndef SIMPLEKERNEL_MATH_H +#define SIMPLEKERNEL_MATH_H #ifdef __cplusplus extern "C" { @@ -14,14 +25,14 @@ extern "C" { // TODO: 更多支持 // TODO: 浮点数 -long long divmoddi4(long long num, long long den, long long *rem_p); -unsigned long long udivmoddi4(unsigned long long num, unsigned long long den, - unsigned long long *rem_p); -unsigned long long udivdi3(unsigned long long num, unsigned long long den); -unsigned long long umoddi3(unsigned long long num, unsigned long long den); +long long divmoddi4(long long _num, long long _den, long long* _rem_p); +unsigned long long udivmoddi4(unsigned long long _num, unsigned long long _den, + unsigned long long* _rem_p); +unsigned long long udivdi3(unsigned long long _num, unsigned long long _den); +unsigned long long umoddi3(unsigned long long _num, unsigned long long _den); #ifdef __cplusplus } #endif -#endif /* _MATH_H_ */ +#endif /* SIMPLEKERNEL_MATH_H */ diff --git a/src/libc/include/stdarg.h b/src/libc/include/stdarg.h index 7dcc49690..53376d274 100644 --- a/src/libc/include/stdarg.h +++ b/src/libc/include/stdarg.h @@ -1,24 +1,34 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// stdarg.h for Simple-XX/SimpleKernel. +/** + * @file stdarg.h + * @brief stdarg 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _STDARG_H_ -#define _STDARG_H_ +#ifndef SIMPLEKERNEL_STDARG_H +#define SIMPLEKERNEL_STDARG_H #ifdef __cplusplus extern "C" { #endif -#define va_list __builtin_va_list -#define va_start(v, l) __builtin_va_start(v, l) -#define va_arg(v, l) __builtin_va_arg(v, l) -#define va_end(v) __builtin_va_end(v) -#define va_copy(d, s) __builtin_va_copy(d, s) +#define va_list __builtin_va_list +#define va_start(_v, _l) __builtin_va_start(_v, _l) +#define va_arg(_v, _l) __builtin_va_arg(_v, _l) +#define va_end(_v) __builtin_va_end(_v) +#define va_copy(_d, _s) __builtin_va_copy(_d, _s) #ifdef __cplusplus } #endif -#endif /* _STDARG_H_ */ +#endif /* SIMPLEKERNEL_STDARG_H */ diff --git a/src/libc/include/stdbool.h b/src/libc/include/stdbool.h index 6af2b77b3..51639a9ee 100644 --- a/src/libc/include/stdbool.h +++ b/src/libc/include/stdbool.h @@ -1,33 +1,44 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Baseed on GCC stdbool.h -// stdbool.h for Simple-XX/SimpleKernel. - -#ifndef _STDBOOL_H_ -#define _STDBOOL_H_ +/** + * @file stdbool.h + * @brief stdbool 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * Baseed on GCC stdbool.h + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_STDBOOL_H +#define SIMPLEKERNEL_STDBOOL_H #ifndef __cplusplus -#define bool _Bool -#define true 1 -#define false 0 +# define bool _Bool +# define true 1 +# define false 0 #else /* __cplusplus */ /* Supporting _Bool in C++ is a GCC extension. */ -#define _Bool bool +# define _Bool bool -#if __cplusplus < 201103L +# if __cplusplus < 201103L /* Defining these macros in C++98 is a GCC extension. */ -#define bool bool -#define false false -#define true true -#endif +# define bool bool +# define false false +# define true true +# endif #endif /* __cplusplus */ /* Signal that all the definitions are present. */ #define __bool_true_false_are_defined 1 -#endif /* _STDBOOL_H_ */ +#endif /* SIMPLEKERNEL_STDBOOL_H */ diff --git a/src/libc/include/stddef.h b/src/libc/include/stddef.h index 15feb9961..1693e100b 100644 --- a/src/libc/include/stddef.h +++ b/src/libc/include/stddef.h @@ -1,53 +1,63 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// stddef.h for Simple-XX/SimpleKernel. - -#ifndef _STDDEF_H_ -#define _STDDEF_H_ +/** + * @file stddef.h + * @brief stddef 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_STDDEF_H +#define SIMPLEKERNEL_STDDEF_H #ifdef __cplusplus extern "C" { #endif #ifndef _PTRDIFF_T -#define _PTRDIFF_T +# define _PTRDIFF_T typedef long ptrdiff_t; #endif #ifndef _SIZE_T -#define _SIZE_T -#undef size_t -#if defined(__i386__) +# define _SIZE_T +# undef size_t +# if defined(__i386__) typedef unsigned int size_t; -#elif defined(__riscv) || defined(__x86_64__) +# elif defined(__riscv) || defined(__x86_64__) typedef long unsigned int size_t; -#endif +# endif #endif #ifndef _SSIZE_T -#define _SSIZE_T -#undef ssize_t -#if defined(__i386__) +# define _SSIZE_T +# undef ssize_t +# if defined(__i386__) typedef int ssize_t; -#elif defined(__riscv) || defined(__x86_64__) +# elif defined(__riscv) || defined(__x86_64__) typedef long int ssize_t; -#endif +# endif #endif #ifndef _SSIZE_T -#define _SSIZE_T -#undef ssize_t +# define _SSIZE_T +# undef ssize_t typedef int ssize_t; #endif #ifndef NULL -#define NULL ((void *)0) +# define NULL ((void*)0) #endif #ifdef __cplusplus } #endif -#endif /* _STDDEF_H_ */ +#endif /* SIMPLEKERNEL_STDDEF_H */ diff --git a/src/libc/include/stdint.h b/src/libc/include/stdint.h index 820e578b4..c9133a36e 100644 --- a/src/libc/include/stdint.h +++ b/src/libc/include/stdint.h @@ -1,26 +1,37 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on GNU C Lib -// stdint.h for Simple-XX/SimpleKernel. - -#ifndef _STDINT_H_ -#define _STDINT_H_ +/** + * @file stdint.h + * @brief stdint 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on GNU C Lib + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_STDINT_H +#define SIMPLEKERNEL_STDINT_H #ifdef __cplusplus extern "C" { #endif #if defined(__x86_64__) || defined(__riscv) -#define __WORDSIZE 64 +# define __WORDSIZE 64 #else -#define __WORDSIZE 32 +# define __WORDSIZE 32 #endif #ifdef __x86_64__ -#define __WORDSIZE_TIME64_COMPAT32 1 +# define __WORDSIZE_TIME64_COMPAT32 1 /* Both x86-64 and x32 use the 64-bit system call interface. */ -#define __SYSCALL_WORDSIZE 64 +# define __SYSCALL_WORDSIZE 64 #endif /* Exact integral types. */ @@ -29,15 +40,15 @@ extern "C" { /* There is some amount of overlap with as known by inet code */ #ifndef __int8_t_defined -#define __int8_t_defined +# define __int8_t_defined typedef signed char int8_t; typedef short int int16_t; typedef int int32_t; -#if __WORDSIZE == 64 +# if __WORDSIZE == 64 typedef long int int64_t; -#else +# else __extension__ typedef long long int int64_t; -#endif +# endif #endif /* Unsigned. */ @@ -45,7 +56,7 @@ typedef unsigned char uint8_t; typedef unsigned short int uint16_t; #ifndef __uint32_t_defined typedef unsigned int uint32_t; -#define __uint32_t_defined +# define __uint32_t_defined #endif #if __WORDSIZE == 64 typedef unsigned long int uint64_t; @@ -103,16 +114,16 @@ __extension__ typedef unsigned long long int uint_fast64_t; /* Types for `void *' pointers. */ #if __WORDSIZE == 64 -#ifndef __intptr_t_defined +# ifndef __intptr_t_defined typedef long int intptr_t; -#define __intptr_t_defined -#endif +# define __intptr_t_defined +# endif typedef unsigned long int uintptr_t; #else -#ifndef __intptr_t_defined +# ifndef __intptr_t_defined typedef int intptr_t; -#define __intptr_t_defined -#endif +# define __intptr_t_defined +# endif typedef unsigned int uintptr_t; #endif @@ -126,97 +137,97 @@ __extension__ typedef unsigned long long int uintmax_t; #endif #ifndef __INT64_C -#if __WORDSIZE == 64 -#define __INT64_C(c) c##L -#define __UINT64_C(c) c##UL -#else -#define __INT64_C(c) c##LL -#define __UINT64_C(c) c##ULL -#endif +# if __WORDSIZE == 64 +# define __INT64_C(c) c##L +# define __UINT64_C(c) c##UL +# else +# define __INT64_C(c) c##LL +# define __UINT64_C(c) c##ULL +# endif #endif /* Limits of integral types. */ /* Minimum of signed integral types. */ -#define INT8_MIN (-128) -#define INT16_MIN (-32767 - 1) -#define INT32_MIN (-2147483647 - 1) -#define INT64_MIN (-__INT64_C(9223372036854775807) - 1) +#define INT8_MIN (-128) +#define INT16_MIN (-32767 - 1) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (-__INT64_C(9223372036854775807) - 1) /* Maximum of signed integral types. */ -#define INT8_MAX (127) -#define INT16_MAX (32767) -#define INT32_MAX (2147483647) -#define INT64_MAX (__INT64_C(9223372036854775807)) +#define INT8_MAX (127) +#define INT16_MAX (32767) +#define INT32_MAX (2147483647) +#define INT64_MAX (__INT64_C(9223372036854775807)) /* Maximum of unsigned integral types. */ -#define UINT8_MAX (255) -#define UINT16_MAX (65535) -#define UINT32_MAX (4294967295U) -#define UINT64_MAX (__UINT64_C(18446744073709551615)) +#define UINT8_MAX (255) +#define UINT16_MAX (65535) +#define UINT32_MAX (4294967295U) +#define UINT64_MAX (__UINT64_C(18446744073709551615)) /* Minimum of signed integral types having a minimum size. */ -#define INT_LEAST8_MIN (-128) -#define INT_LEAST16_MIN (-32767 - 1) -#define INT_LEAST32_MIN (-2147483647 - 1) -#define INT_LEAST64_MIN (-__INT64_C(9223372036854775807) - 1) +#define INT_LEAST8_MIN (-128) +#define INT_LEAST16_MIN (-32767 - 1) +#define INT_LEAST32_MIN (-2147483647 - 1) +#define INT_LEAST64_MIN (-__INT64_C(9223372036854775807) - 1) /* Maximum of signed integral types having a minimum size. */ -#define INT_LEAST8_MAX (127) -#define INT_LEAST16_MAX (32767) -#define INT_LEAST32_MAX (2147483647) -#define INT_LEAST64_MAX (__INT64_C(9223372036854775807)) +#define INT_LEAST8_MAX (127) +#define INT_LEAST16_MAX (32767) +#define INT_LEAST32_MAX (2147483647) +#define INT_LEAST64_MAX (__INT64_C(9223372036854775807)) /* Maximum of unsigned integral types having a minimum size. */ -#define UINT_LEAST8_MAX (255) +#define UINT_LEAST8_MAX (255) #define UINT_LEAST16_MAX (65535) #define UINT_LEAST32_MAX (4294967295U) #define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615)) /* Minimum of fast signed integral types having a minimum size. */ -#define INT_FAST8_MIN (-128) +#define INT_FAST8_MIN (-128) #if __WORDSIZE == 64 -#define INT_FAST16_MIN (-9223372036854775807L - 1) -#define INT_FAST32_MIN (-9223372036854775807L - 1) +# define INT_FAST16_MIN (-9223372036854775807L - 1) +# define INT_FAST32_MIN (-9223372036854775807L - 1) #else -#define INT_FAST16_MIN (-2147483647 - 1) -#define INT_FAST32_MIN (-2147483647 - 1) +# define INT_FAST16_MIN (-2147483647 - 1) +# define INT_FAST32_MIN (-2147483647 - 1) #endif #define INT_FAST64_MIN (-__INT64_C(9223372036854775807) - 1) /* Maximum of fast signed integral types having a minimum size. */ -#define INT_FAST8_MAX (127) +#define INT_FAST8_MAX (127) #if __WORDSIZE == 64 -#define INT_FAST16_MAX (9223372036854775807L) -#define INT_FAST32_MAX (9223372036854775807L) +# define INT_FAST16_MAX (9223372036854775807L) +# define INT_FAST32_MAX (9223372036854775807L) #else -#define INT_FAST16_MAX (2147483647) -#define INT_FAST32_MAX (2147483647) +# define INT_FAST16_MAX (2147483647) +# define INT_FAST32_MAX (2147483647) #endif #define INT_FAST64_MAX (__INT64_C(9223372036854775807)) /* Maximum of fast unsigned integral types having a minimum size. */ #define UINT_FAST8_MAX (255) #if __WORDSIZE == 64 -#define UINT_FAST16_MAX (18446744073709551615UL) -#define UINT_FAST32_MAX (18446744073709551615UL) +# define UINT_FAST16_MAX (18446744073709551615UL) +# define UINT_FAST32_MAX (18446744073709551615UL) #else -#define UINT_FAST16_MAX (4294967295U) -#define UINT_FAST32_MAX (4294967295U) +# define UINT_FAST16_MAX (4294967295U) +# define UINT_FAST32_MAX (4294967295U) #endif #define UINT_FAST64_MAX (__UINT64_C(18446744073709551615)) /* Values to test for integral types holding `void *' pointer. */ #if __WORDSIZE == 64 -#define INTPTR_MIN (-9223372036854775807L - 1) -#define INTPTR_MAX (9223372036854775807L) -#define UINTPTR_MAX (18446744073709551615UL) +# define INTPTR_MIN (-9223372036854775807L - 1) +# define INTPTR_MAX (9223372036854775807L) +# define UINTPTR_MAX (18446744073709551615UL) #else -#define INTPTR_MIN (-2147483647 - 1) -#define INTPTR_MAX (2147483647) -#define UINTPTR_MAX (4294967295U) +# define INTPTR_MIN (-2147483647 - 1) +# define INTPTR_MAX (2147483647) +# define UINTPTR_MAX (4294967295U) #endif /* Minimum for largest signed integral type. */ -#define INTMAX_MIN (-__INT64_C(9223372036854775807) - 1) +#define INTMAX_MIN (-__INT64_C(9223372036854775807) - 1) /* Maximum for largest signed integral type. */ -#define INTMAX_MAX (__INT64_C(9223372036854775807)) +#define INTMAX_MAX (__INT64_C(9223372036854775807)) /* Maximum for largest unsigned integral type. */ #define UINTMAX_MAX (__UINT64_C(18446744073709551615)) @@ -225,11 +236,11 @@ __extension__ typedef unsigned long long int uintmax_t; /* Limits of `ptrdiff_t' type. */ #if __WORDSIZE == 64 -#define PTRDIFF_MIN (-9223372036854775807L - 1) -#define PTRDIFF_MAX (9223372036854775807L) +# define PTRDIFF_MIN (-9223372036854775807L - 1) +# define PTRDIFF_MAX (9223372036854775807L) #else -#define PTRDIFF_MIN (-2147483647 - 1) -#define PTRDIFF_MAX (2147483647) +# define PTRDIFF_MIN (-2147483647 - 1) +# define PTRDIFF_MAX (2147483647) #endif /* Limits of `sig_atomic_t'. */ @@ -238,57 +249,57 @@ __extension__ typedef unsigned long long int uintmax_t; /* Limit of `size_t' type. */ #if __WORDSIZE == 64 -#define SIZE_MAX (18446744073709551615UL) +# define SIZE_MAX (18446744073709551615UL) #else -#ifdef __WORDSIZE32_SIZE_ULONG -#define SIZE_MAX (4294967295UL) -#else -#define SIZE_MAX (4294967295U) -#endif +# ifdef __WORDSIZE32_SIZE_ULONG +# define SIZE_MAX (4294967295UL) +# else +# define SIZE_MAX (4294967295U) +# endif #endif /* Limits of `wchar_t'. */ #ifndef WCHAR_MIN /* These constants might also be defined in . */ -#define WCHAR_MIN __WCHAR_MIN -#define WCHAR_MAX __WCHAR_MAX +# define WCHAR_MIN __WCHAR_MIN +# define WCHAR_MAX __WCHAR_MAX #endif /* Limits of `wint_t'. */ -#define WINT_MIN (0u) -#define WINT_MAX (4294967295u) +#define WINT_MIN (0u) +#define WINT_MAX (4294967295u) /* Signed. */ -#define INT8_C(c) c -#define INT16_C(c) c -#define INT32_C(c) c +#define INT8_C(_c) _c +#define INT16_C(_c) _c +#define INT32_C(_c) _c #if __WORDSIZE == 64 -#define INT64_C(c) c##L +# define INT64_C(_c) _c##L #else -#define INT64_C(c) c##LL +# define INT64_C(_c) _c##LL #endif /* Unsigned. */ -#define UINT8_C(c) c -#define UINT16_C(c) c -#define UINT32_C(c) c##U +#define UINT8_C(_c) _c +#define UINT16_C(_c) _c +#define UINT32_C(_c) _c##U #if __WORDSIZE == 64 -#define UINT64_C(c) c##UL +# define UINT64_C(_c) _c##UL #else -#define UINT64_C(c) c##ULL +# define UINT64_C(_c) _c##ULL #endif /* Maximal type. */ #if __WORDSIZE == 64 -#define INTMAX_C(c) c##L -#define UINTMAX_C(c) c##UL +# define INTMAX_C(_c) _c##L +# define UINTMAX_C(_c) _c##UL #else -#define INTMAX_C(c) c##LL -#define UINTMAX_C(c) c##ULL +# define INTMAX_C(_c) _c##LL +# define UINTMAX_C(_c) _c##ULL #endif #ifdef __cplusplus } #endif -#endif /* _STDINT_H_ */ +#endif /* SIMPLEKERNEL_STDINT_H */ diff --git a/src/libc/include/stdio.h b/src/libc/include/stdio.h index a52d368bc..1b51ae3a2 100644 --- a/src/libc/include/stdio.h +++ b/src/libc/include/stdio.h @@ -1,19 +1,30 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/mpaland/printf -// stdio.h for Simple-XX/SimpleKernel. +/** + * @file stdio.h + * @brief stdio 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/mpaland/printf + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _STDIO_H_ -#define _STDIO_H_ +#ifndef SIMPLEKERNEL_STDIO_H +#define SIMPLEKERNEL_STDIO_H #ifdef __cplusplus extern "C" { #endif -#include "stdint.h" -#include "stddef.h" #include "stdarg.h" +#include "stddef.h" +#include "stdint.h" /** * Tiny sprintf implementation @@ -25,7 +36,7 @@ extern "C" { * null character */ #define sprintf sprintf_ -int sprintf_(char *buffer, const char *format, ...); +int sprintf_(char* _buffer, const char* _format, ...); /** * Tiny snprintf/vsnprintf implementation @@ -38,23 +49,23 @@ int sprintf_(char *buffer, const char *format, ...); * than count indicates truncation. Only when the returned value is non-negative * and less than count, the string has been completely written. */ -#define snprintf snprintf_ +#define snprintf snprintf_ #define vsnprintf vsnprintf_ -int snprintf_(char *buffer, size_t count, const char *format, ...); -int vsnprintf_(char *buffer, size_t count, const char *format, va_list va); -int _vsnprintf(char *buffer, const size_t maxlen, const char *format, - va_list va); +int snprintf_(char* _buffer, size_t _count, const char* _format, ...); +int vsnprintf_(char* _buffer, size_t _count, const char* _format, va_list _va); +int _vsnprintf(char* _buffer, const size_t _maxlen, const char* _format, + va_list _va); -int printf(const char *fmt, ...); +int32_t printf(const char* _fmt, ...); -int info(const char *fmt, ...); +int32_t info(const char* _fmt, ...); -int warn(const char *fmt, ...); +int32_t warn(const char* _fmt, ...); -int err(const char *fmt, ...); +int32_t err(const char* _fmt, ...); #ifdef __cplusplus } #endif -#endif /* _STDIO_H_ */ +#endif /* SIMPLEKERNEL_STDIO_H */ diff --git a/src/libc/include/stdlib.h b/src/libc/include/stdlib.h index 369a96747..726ca670b 100644 --- a/src/libc/include/stdlib.h +++ b/src/libc/include/stdlib.h @@ -1,33 +1,47 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// stdlib.h for Simple-XX/SimpleKernel. - -#ifndef _STDLIB_H_ -#define _STDLIB_H_ +/** + * @file stdlib.h + * @brief stdlib 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_STDLIB_H +#define SIMPLEKERNEL_STDLIB_H #ifdef __cplusplus extern "C" { #endif -#include "stdint.h" #include "stddef.h" +#include "stdint.h" int abs(int); -int atoi(const char *); -long atol(const char *); -long long atoll(const char *); -int itoa(int num, char *str, int len, int base); -long strtol(const char *nptr, char **endptr, int base); -long long strtoll(const char *nptr, char **endptr, int base); +int atoi(const char*); +long atol(const char*); +long long atoll(const char*); +int itoa(int _num, char* _str, int _len, int _base); +long strtol(const char* _nptr, char** _endptr, int _base); +long long strtoll(const char* _nptr, char** _endptr, int _base); + +void* malloc(size_t size); + +void free(void* ptr); -void *malloc(size_t size); +void* kmalloc(size_t size); -void free(void *ptr); +void kfree(void* ptr); #ifdef __cplusplus } #endif -#endif /* _STDLIB_H_ */ +#endif /* SIMPLEKERNEL_STDLIB_H */ diff --git a/src/libc/include/string.h b/src/libc/include/string.h index 904c44be6..5881a4742 100644 --- a/src/libc/include/string.h +++ b/src/libc/include/string.h @@ -1,41 +1,51 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// string.h for Simple-XX/SimpleKernel. +/** + * @file string.h + * @brief string 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#ifndef _STRING_H_ -#define _STRING_H_ +#ifndef SIMPLEKERNEL_STRING_H +#define SIMPLEKERNEL_STRING_H #ifdef __cplusplus extern "C" { #endif -#include "stdint.h" #include "stddef.h" +#include "stdint.h" -extern void *memcpy(void *dest, const void *src, size_t len); -extern void *memset(void *dest, int val, size_t len); -extern int memcmp(const void *str1, const void *str2, size_t count); -extern void *memmove(void *dest, const void *src, size_t len); -extern void bzero(void *dest, uint32_t len); +extern void* memcpy(void* _dest, const void* _src, size_t _len); +extern void* memset(void* _dest, int val, size_t _len); +extern int memcmp(const void* _str1, const void* _str2, size_t _count); +extern void* memmove(void* _dest, const void* _src, size_t _len); +extern void bzero(void* _dest, uint32_t _len); // 字符串比较 -extern int strcmp(const char *src, const char *dest); -extern int strncmp(const char *s1, const char *s2, size_t n); -extern char *strcpy(char *dest, const char *src); -extern char *strncpy(char *s1, const char *s2, size_t n); +extern int strcmp(const char* _src, const char* _dest); +extern int strncmp(const char* _s1, const char* _s2, size_t _n); +extern char* strcpy(char* _dest, const char* _src); +extern char* strncpy(char* _s1, const char* _s2, size_t _n); // 字符串合并 -extern char *strcat(char *dest, const char *src); -extern char *strchr(const char *s, int c); +extern char* strcat(char* _dest, const char* _src); +extern char* strchr(const char* _s, int _c); // length of string -extern size_t strlen(const char *src); -extern size_t strnlen(const char *str, size_t maxlen); -extern void backspace(char *src); -extern void append(char *src, char dest); -extern void strrev(char *str); +extern size_t strlen(const char* _src); +extern size_t strnlen(const char* _str, size_t _maxlen); +extern void backspace(char* _src); +extern void append(char* _src, char _dest); +extern void strrev(char* _str); #ifdef __cplusplus } #endif -#endif /* _STRING_H_ */ +#endif /* SIMPLEKERNEL_STRING_H */ diff --git a/src/libc/src/math/math.c b/src/libc/src/math/math.c index 0ecae481b..0a26daa61 100644 --- a/src/libc/src/math/math.c +++ b/src/libc/src/math/math.c @@ -1,8 +1,19 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on libgcc -// math.c for Simple-XX/SimpleKernel. +/** + * @file math.c + * @brief math 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on libgcc + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ #ifdef __cplusplus extern "C" { @@ -10,67 +21,69 @@ extern "C" { #include "math.h" -long long divmoddi4(long long num, long long den, long long *rem_p) { +long long divmoddi4(long long _num, long long _den, long long* _rem_p) { int minus = 0; long long v; - if (num < 0) { - num = -num; + if (_num < 0) { + _num = -_num; minus = 1; } - if (den < 0) { - den = -den; + if (_den < 0) { + _den = -_den; minus ^= 1; } - v = udivmoddi4(num, den, (unsigned long long *)rem_p); + v = udivmoddi4(_num, _den, (unsigned long long*)_rem_p); if (minus) { v = -v; - if (rem_p) - *rem_p = -(*rem_p); + if (_rem_p) { + *_rem_p = -(*_rem_p); + } } return v; } // BUG: 在 x86_64 下观察到了精度损失 -unsigned long long udivmoddi4(unsigned long long num, unsigned long long den, - unsigned long long *rem_p) { +unsigned long long udivmoddi4(unsigned long long _num, unsigned long long _den, + unsigned long long* _rem_p) { unsigned long long quot = 0, qbit = 1; - if (den == 0) { - return 1 / ((unsigned)den); /* Intentional divide by zero, without + if (_den == 0) { + return 1 / ((unsigned)_den); /* Intentional divide by zero, without triggering a compiler warning which would abort the build */ } /* Left-justify denominator and count shift */ - while ((long long)den >= 0) { - den <<= 1; + while ((long long)_den >= 0) { + _den <<= 1; qbit <<= 1; } while (qbit) { - if (den <= num) { - num -= den; + if (_den <= _num) { + _num -= _den; quot += qbit; } - den >>= 1; + _den >>= 1; qbit >>= 1; } - if (rem_p) - *rem_p = num; + if (_rem_p) { + *_rem_p = _num; + } return quot; } -unsigned long long udivdi3(unsigned long long num, unsigned long long den) { - return udivmoddi4(num, den, 0); +unsigned long long udivdi3(unsigned long long _num, unsigned long long _den) { + return udivmoddi4(_num, _den, 0); } -unsigned long long umoddi3(unsigned long long num, unsigned long long den) { +unsigned long long umoddi3(unsigned long long _num, unsigned long long _den) { unsigned long long v; - (void)udivmoddi4(num, den, &v); + (void)udivmoddi4(_num, _den, &v); return v; } diff --git a/src/libc/src/stdio/vsprintf.c b/src/libc/src/stdio/vsprintf.c index ca2e56db3..8420ac755 100644 --- a/src/libc/src/stdio/vsprintf.c +++ b/src/libc/src/stdio/vsprintf.c @@ -1,369 +1,385 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/mpaland/printf -// vsprintf.c for Simple-XX/SimpleKernel. +/** + * @file vsprintf.c + * @brief vsprintf 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/mpaland/printf + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ #ifdef __cplusplus extern "C" { #endif -#include "stdbool.h" -#include "stdint.h" +#include "math.h" #include "stdarg.h" +#include "stdbool.h" #include "stddef.h" -#include "math.h" +#include "stdint.h" #include "stdio.h" // 'ntoa' conversion buffer size, this must be big enough to hold one converted // numeric number including padded zeros (dynamically created on stack) // default: 32 byte #ifndef PRINTF_NTOA_BUFFER_SIZE -#define PRINTF_NTOA_BUFFER_SIZE 32U +# define PRINTF_NTOA_BUFFER_SIZE 32U #endif // 'ftoa' conversion buffer size, this must be big enough to hold one converted // float number including padded zeros (dynamically created on stack) // default: 32 byte #ifndef PRINTF_FTOA_BUFFER_SIZE -#define PRINTF_FTOA_BUFFER_SIZE 32U +# define PRINTF_FTOA_BUFFER_SIZE 32U #endif // support for the floating point type (%f) // default: activated #define PRINTF_DISABLE_SUPPORT_FLOAT #ifndef PRINTF_DISABLE_SUPPORT_FLOAT -#define PRINTF_SUPPORT_FLOAT +# define PRINTF_SUPPORT_FLOAT #endif // support for exponential floating point notation (%e/%g) // default: activated #ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL -#define PRINTF_SUPPORT_EXPONENTIAL +# define PRINTF_SUPPORT_EXPONENTIAL #endif // define the default floating point precision // default: 6 digits #ifndef PRINTF_DEFAULT_FLOAT_PRECISION -#define PRINTF_DEFAULT_FLOAT_PRECISION 6U +# define PRINTF_DEFAULT_FLOAT_PRECISION 6U #endif // define the largest float suitable to print with %f // default: 1e9 #ifndef PRINTF_MAX_FLOAT -#define PRINTF_MAX_FLOAT 1e9 +# define PRINTF_MAX_FLOAT 1e9 #endif // support for the long long types (%llu or %p) // default: activated #ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG -#define PRINTF_SUPPORT_LONG_LONG +# define PRINTF_SUPPORT_LONG_LONG #endif // support for the ptrdiff_t type (%t) // ptrdiff_t is normally defined in as long or long long type // default: activated #ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T -#define PRINTF_SUPPORT_PTRDIFF_T +# define PRINTF_SUPPORT_PTRDIFF_T #endif /////////////////////////////////////////////////////////////////////////////// // internal flag definitions -#define FLAGS_ZEROPAD (1U << 0U) -#define FLAGS_LEFT (1U << 1U) -#define FLAGS_PLUS (1U << 2U) -#define FLAGS_SPACE (1U << 3U) -#define FLAGS_HASH (1U << 4U) +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) #define FLAGS_UPPERCASE (1U << 5U) -#define FLAGS_CHAR (1U << 6U) -#define FLAGS_SHORT (1U << 7U) -#define FLAGS_LONG (1U << 8U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) #define FLAGS_LONG_LONG (1U << 9U) #define FLAGS_PRECISION (1U << 10U) #define FLAGS_ADAPT_EXP (1U << 11U) // import float.h for DBL_MAX #if defined(PRINTF_SUPPORT_FLOAT) -#include "float.h" +# include "float.h" #endif // output function type -typedef void (*out_fct_type)(char character, void *buffer, size_t idx, - size_t maxlen); +typedef void (*out_fct_type)(char _character, void* _buffer, size_t _idx, + size_t _maxlen); // wrapper (used as buffer) for output function type typedef struct { - void (*fct)(char character, void *arg); - void *arg; + void (*fct)(char _character, void* arg); + void* arg; } out_fct_wrap_type; // internal buffer output -static inline void _out_buffer(char character, void *buffer, size_t idx, - size_t maxlen) { - if (idx < maxlen) { - ((char *)buffer)[idx] = character; +inline static void +_out_buffer(char _character, void* _buffer, size_t _idx, size_t _maxlen) { + if (_idx < _maxlen) { + ((char*)_buffer)[_idx] = _character; } } // internal null output -static inline void _out_null(char character, void *buffer, size_t idx, - size_t maxlen) { - (void)character; - (void)buffer; - (void)idx; - (void)maxlen; +inline static void +_out_null(char _character, void* _buffer, size_t _idx, size_t _maxlen) { + (void)_character; + (void)_buffer; + (void)_idx; + (void)_maxlen; } // internal secure strlen // \return The length of the string (excluding the terminating 0) limited by // 'maxsize' -static inline unsigned int _strnlen_s(const char *str, size_t maxsize) { - const char *s; - for (s = str; *s && maxsize--; ++s) +inline static unsigned int _strnlen_s(const char* _str, size_t _maxsize) { + const char* s; + for (s = _str; *s && _maxsize--; ++s) ; - return (unsigned int)(s - str); + return (unsigned int)(s - _str); } // internal test if char is a digit (0-9) // \return true if char is a digit -static inline bool _is_digit(char ch) { - return (ch >= '0') && (ch <= '9'); +inline static bool _is_digit(char _ch) { + return (_ch >= '0') && (_ch <= '9'); } // internal ASCII string to unsigned int conversion -static unsigned int _atoi(const char **str) { +static unsigned int _atoi(const char** _str) { unsigned int i = 0U; - while (_is_digit(**str)) { - i = i * 10U + (unsigned int)(*((*str)++) - '0'); + while (_is_digit(**_str)) { + i = i * 10U + (unsigned int)(*((*_str)++) - '0'); } return i; } // output the specified string in reverse, taking care of any zero-padding -static size_t _out_rev(out_fct_type out, char *buffer, size_t idx, - size_t maxlen, const char *buf, size_t len, - unsigned int width, unsigned int flags) { - const size_t start_idx = idx; +static size_t _out_rev(out_fct_type _out, char* _buffer, size_t _idx, + size_t _maxlen, const char* _buf, size_t _len, + unsigned int _width, unsigned int _flags) { + const size_t start_idx = _idx; - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - for (size_t i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); + // pad spaces up to given _width + if (!(_flags & FLAGS_LEFT) && !(_flags & FLAGS_ZEROPAD)) { + for (size_t i = _len; i < _width; i++) { + _out(' ', _buffer, _idx++, _maxlen); } } // reverse string - while (len) { - out(buf[--len], buffer, idx++, maxlen); + while (_len) { + _out(_buf[--_len], _buffer, _idx++, _maxlen); } // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) { - out(' ', buffer, idx++, maxlen); + if (_flags & FLAGS_LEFT) { + while (_idx - start_idx < _width) { + _out(' ', _buffer, _idx++, _maxlen); } } - return idx; + return _idx; } // internal itoa format -static size_t _ntoa_format(out_fct_type out, char *buffer, size_t idx, - size_t maxlen, char *buf, size_t len, bool negative, - unsigned int base, unsigned int prec, - unsigned int width, unsigned int flags) { +static size_t +_ntoa_format(out_fct_type _out, char* _buffer, size_t _idx, size_t _maxlen, + char* _buf, size_t _len, bool _negative, unsigned int _base, + unsigned int _prec, unsigned int _width, unsigned int _flags) { // pad leading zeros - if (!(flags & FLAGS_LEFT)) { - if (width && (flags & FLAGS_ZEROPAD) && - (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; + if (!(_flags & FLAGS_LEFT)) { + if (_width && (_flags & FLAGS_ZEROPAD) + && (_negative || (_flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + _width--; } - while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; + while ((_len < _prec) && (_len < PRINTF_NTOA_BUFFER_SIZE)) { + _buf[_len++] = '0'; } - while ((flags & FLAGS_ZEROPAD) && (len < width) && - (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; + while ((_flags & FLAGS_ZEROPAD) && (_len < _width) + && (_len < PRINTF_NTOA_BUFFER_SIZE)) { + _buf[_len++] = '0'; } } // handle hash - if (flags & FLAGS_HASH) { - if (!(flags & FLAGS_PRECISION) && len && - ((len == prec) || (len == width))) { - len--; - if (len && (base == 16U)) { - len--; + if (_flags & FLAGS_HASH) { + if (!(_flags & FLAGS_PRECISION) && _len + && ((_len == _prec) || (_len == _width))) { + _len--; + if (_len && (_base == 16U)) { + _len--; } } - if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && - (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'x'; + if ((_base == 16U) && !(_flags & FLAGS_UPPERCASE) + && (_len < PRINTF_NTOA_BUFFER_SIZE)) { + _buf[_len++] = 'x'; } - else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && - (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'X'; + else if ((_base == 16U) && (_flags & FLAGS_UPPERCASE) + && (_len < PRINTF_NTOA_BUFFER_SIZE)) { + _buf[_len++] = 'X'; } - else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'b'; + else if ((_base == 2U) && (_len < PRINTF_NTOA_BUFFER_SIZE)) { + _buf[_len++] = 'b'; } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - buf[len++] = '0'; + if (_len < PRINTF_NTOA_BUFFER_SIZE) { + _buf[_len++] = '0'; } } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; + if (_len < PRINTF_NTOA_BUFFER_SIZE) { + if (_negative) { + _buf[_len++] = '-'; } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists + else if (_flags & FLAGS_PLUS) { + _buf[_len++] = '+'; // ignore the space if the '+' exists } - else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; + else if (_flags & FLAGS_SPACE) { + _buf[_len++] = ' '; } } - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); + return _out_rev(_out, _buffer, _idx, _maxlen, _buf, _len, _width, _flags); } // internal itoa for 'long' type -static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx, - size_t maxlen, unsigned long value, bool negative, - unsigned long base, unsigned int prec, - unsigned int width, unsigned int flags) { +static size_t +_ntoa_long(out_fct_type _out, char* _buffer, size_t _idx, size_t _maxlen, + unsigned long _value, bool _negative, unsigned long _base, + unsigned int _prec, unsigned int _width, unsigned int _flags) { char buf[PRINTF_NTOA_BUFFER_SIZE]; size_t len = 0U; // no hash for 0 values - if (!value) { - flags &= ~FLAGS_HASH; + if (!_value) { + _flags &= ~FLAGS_HASH; } - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { + // write if precision != 0 and _value is != 0 + if (!(_flags & FLAGS_PRECISION) || _value) { do { - const char digit = (char)(value % base); - buf[len++] = - digit < 10 ? '0' + digit - : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + const char digit = (char)(_value % _base); + buf[len++] = digit < 10 + ? '0' + digit + : (_flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + _value /= _base; + } while (_value && (len < PRINTF_NTOA_BUFFER_SIZE)); } - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, - (unsigned int)base, prec, width, flags); + return _ntoa_format(_out, _buffer, _idx, _maxlen, buf, len, _negative, + (unsigned int)_base, _prec, _width, _flags); } // internal itoa for 'long long' type #if defined(PRINTF_SUPPORT_LONG_LONG) -static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx, - size_t maxlen, unsigned long long value, - bool negative, unsigned long long base, - unsigned int prec, unsigned int width, - unsigned int flags) { +static size_t +_ntoa_long_long(out_fct_type _out, char* _buffer, size_t _idx, size_t _maxlen, + unsigned long long _value, bool _negative, + unsigned long long _base, unsigned int _prec, + unsigned int _width, unsigned int _flags) { char buf[PRINTF_NTOA_BUFFER_SIZE]; size_t len = 0U; // no hash for 0 values - if (!value) { - flags &= ~FLAGS_HASH; + if (!_value) { + _flags &= ~FLAGS_HASH; } -#if defined(__i386__) - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { +# if defined(__i386__) + // write if precision != 0 and _value is != 0 + if (!(_flags & FLAGS_PRECISION) || _value) { do { unsigned long long no; - unsigned long long t = udivmoddi4(value, base, &no); + unsigned long long t = udivmoddi4(_value, _base, &no); const char digit = (char)t; - buf[len++] = - digit < 10 ? '0' + digit - : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value = udivdi3(value, base); - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + buf[len++] = digit < 10 + ? '0' + digit + : (_flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + _value = udivdi3(_value, _base); + } while (_value && (len < PRINTF_NTOA_BUFFER_SIZE)); } -#else +# else // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { + if (!(_flags & FLAGS_PRECISION) || _value) { do { - const char digit = (char)(value % base); - buf[len++] = - digit < 10 ? '0' + digit - : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } -#endif - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, - (unsigned int)base, prec, width, flags); + const char digit = (char)(_value % _base); + buf[len++] = digit < 10 + ? '0' + digit + : (_flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + _value /= _base; + } while (_value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } +# endif + return _ntoa_format(_out, _buffer, _idx, _maxlen, buf, len, _negative, + (unsigned int)_base, _prec, _width, _flags); } -#endif // PRINTF_SUPPORT_LONG_LONG +#endif // PRINTF_SUPPORT_LONG_LONG #if defined(PRINTF_SUPPORT_FLOAT) -#if defined(PRINTF_SUPPORT_EXPONENTIAL) +# if defined(PRINTF_SUPPORT_EXPONENTIAL) // forward declaration so that _ftoa can switch to exp notation for values > // PRINTF_MAX_FLOAT -static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, - double value, unsigned int prec, unsigned int width, - unsigned int flags); -#endif +static size_t _etoa(out_fct_type _out, char* _buffer, size_t _idx, + size_t _maxlen, double _value, unsigned int _prec, + unsigned int _width, unsigned int _flags); +# endif // internal ftoa for fixed decimal floating point -static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, - double value, unsigned int prec, unsigned int width, - unsigned int flags) { - char buf[PRINTF_FTOA_BUFFER_SIZE]; - size_t len = 0U; - double diff = 0.0; +static size_t _ftoa(out_fct_type _out, char* _buffer, size_t _idx, + size_t _maxlen, double _value, unsigned int _prec, + unsigned int _width, unsigned int _flags) { + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; // powers of 10 - static const double pow10[] = {1, 10, 100, 1000, - 10000, 100000, 1000000, 10000000, - 100000000, 1000000000}; + static const double pow10[] + = { 1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000, 1000000000 }; // test for special values - if (value != value) - return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); - if (value < -DBL_MAX) - return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); - if (value > DBL_MAX) - return _out_rev(out, buffer, idx, maxlen, - (flags & FLAGS_PLUS) ? "fni+" : "fni", - (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + if (_value != _value) { + return _out_rev(_out, _buffer, _idx, _maxlen, "nan", 3, _width, _flags); + } + if (_value < -DBL_MAX) { + return _out_rev(_out, _buffer, _idx, _maxlen, "fni-", 4, _width, + _flags); + } + if (_value > DBL_MAX) { + return _out_rev(_out, _buffer, _idx, _maxlen, + (_flags & FLAGS_PLUS) ? "fni+" : "fni", + (_flags & FLAGS_PLUS) ? 4U : 3U, _width, _flags); + } // test for very large values // standard printf behavior is to print EVERY whole number digit -- which // could be 100s of characters overflowing your buffers == bad - if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { -#if defined(PRINTF_SUPPORT_EXPONENTIAL) - return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); -#else + if ((_value > PRINTF_MAX_FLOAT) || (_value < -PRINTF_MAX_FLOAT)) { +# if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(_out, _buffer, _idx, _maxlen, _value, _prec, _width, + _flags); +# else return 0U; -#endif +# endif } // test for negative bool negative = false; - if (value < 0) { + if (_value < 0) { negative = true; - value = 0 - value; + _value = 0 - _value; } // set default precision, if not set explicitly - if (!(flags & FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; + if (!(_flags & FLAGS_PRECISION)) { + _prec = PRINTF_DEFAULT_FLOAT_PRECISION; } // limit precision to 9, cause a prec >= 10 can lead to overflow errors - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (_prec > 9U)) { buf[len++] = '0'; - prec--; + _prec--; } - int whole = (int)value; - double tmp = (value - whole) * pow10[prec]; + int whole = (int)_value; + double tmp = (_value - whole) * pow10[_prec]; unsigned long frac = (unsigned long)tmp; diff = tmp - frac; @@ -383,7 +399,7 @@ static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, } if (prec == 0U) { - diff = value - (double)whole; + diff = _value - (double)whole; if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { // exactly 0.5 and ODD, then round up // 1.5 -> 2, but 2.5 -> 2 @@ -419,11 +435,11 @@ static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, } // pad leading zeros - if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { - if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; + if (!(_flags & FLAGS_LEFT) && (_flags & FLAGS_ZEROPAD)) { + if (_width && (negative || (_flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + _width--; } - while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + while ((len < _width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { buf[len++] = '0'; } } @@ -432,37 +448,38 @@ static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, if (negative) { buf[len++] = '-'; } - else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists + else if (_flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists } - else if (flags & FLAGS_SPACE) { + else if (_flags & FLAGS_SPACE) { buf[len++] = ' '; } } - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); + return _out_rev(_out, _buffer, _idx, _maxlen, buf, len, _width, _flags); } -#if defined(PRINTF_SUPPORT_EXPONENTIAL) +# if defined(PRINTF_SUPPORT_EXPONENTIAL) // internal ftoa variant for exponential floating-point type, contributed by // Martijn Jasperse -static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, - double value, unsigned int prec, unsigned int width, - unsigned int flags) { +static size_t _etoa(out_fct_type _out, char* _buffer, size_t _idx, + size_t _maxlen, double _value, unsigned int _prec, + unsigned int _width, unsigned int _flags) { // check for NaN and special values - if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { - return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + if ((_value != _value) || (_value > DBL_MAX) || (_value < -DBL_MAX)) { + return _ftoa(_out, _buffer, _idx, _maxlen, _value, _prec, _width, + _flags); } // determine the sign - const bool negative = value < 0; + const bool negative = _value < 0; if (negative) { - value = -value; + _value = -_value; } // default precision - if (!(flags & FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; + if (!(_flags & FLAGS_PRECISION)) { + _prec = PRINTF_DEFAULT_FLOAT_PRECISION; } // determine the decimal exponent @@ -473,24 +490,24 @@ static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double F; } conv; - conv.F = value; - int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 - conv.U = (conv.U & ((1ULL << 52U) - 1U)) | - (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + conv.F = _value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) + | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) // now approximate log10 from the log2 integer part and an expansion of ln // around 1.5 - int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + - (conv.F - 1.5) * 0.289529654602168); + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + + (conv.F - 1.5) * 0.289529654602168); // now we want to compute 10^expval but we want to be sure it won't overflow - exp2 = (int)(expval * 3.321928094887362 + 0.5); - const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; - const double z2 = z * z; - conv.U = (uint64_t)(exp2 + 1023) << 52U; + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; // compute exp(z) using continued fractions, see // https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex - conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); // correct for rounding errors - if (value < conv.F) { + if (_value < conv.F) { expval--; conv.F /= 10; } @@ -500,31 +517,31 @@ static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; // in "%g" mode, "prec" is the number of *significant figures* not decimals - if (flags & FLAGS_ADAPT_EXP) { + if (_flags & FLAGS_ADAPT_EXP) { // do we want to fall-back to "%f" mode? - if ((value >= 1e-4) && (value < 1e6)) { - if ((int)prec > expval) { - prec = (unsigned)((int)prec - expval - 1); + if ((_value >= 1e-4) && (_value < 1e6)) { + if ((int)_prec > expval) { + _prec = (unsigned)((int)_prec - expval - 1); } else { - prec = 0; + _prec = 0; } - flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + _flags |= FLAGS_PRECISION; // make sure _ftoa respects precision // no characters in exponent minwidth = 0U; expval = 0; } else { // we use one sigfig for the whole part - if ((prec > 0) && (flags & FLAGS_PRECISION)) { - --prec; + if ((_prec > 0) && (_flags & FLAGS_PRECISION)) { + --_prec; } } } // will everything fit? - unsigned int fwidth = width; - if (width > minwidth) { + unsigned int fwidth = _width; + if (_width > minwidth) { // we didn't fall-back so subtract the characters required for the // exponent fwidth -= minwidth; @@ -533,93 +550,94 @@ static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, // not enough characters, so go back to default sizing fwidth = 0U; } - if ((flags & FLAGS_LEFT) && minwidth) { + if ((_flags & FLAGS_LEFT) && minwidth) { // if we're padding on the right, DON'T pad the floating part fwidth = 0U; } // rescale the float value if (expval) { - value /= conv.F; + _value /= conv.F; } // output the floating part - const size_t start_idx = idx; - idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, - fwidth, flags & ~FLAGS_ADAPT_EXP); + const size_t start_idx = _idx; + _idx = _ftoa(_out, _buffer, _idx, _maxlen, negative ? -_value : _value, + _prec, fwidth, _flags & ~FLAGS_ADAPT_EXP); // output the exponent part if (minwidth) { // output the exponential symbol - out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + _out((_flags & FLAGS_UPPERCASE) ? 'E' : 'e', _buffer, _idx++, _maxlen); // output the exponent value - idx = _ntoa_long(out, buffer, idx, maxlen, - (expval < 0) ? -expval : expval, expval < 0, 10, 0, - minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS); + _idx = _ntoa_long(_out, _buffer, _idx, _maxlen, + (expval < 0) ? -expval : expval, expval < 0, 10, 0, + minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS); // might need to right-pad spaces - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) - out(' ', buffer, idx++, maxlen); + if (_flags & FLAGS_LEFT) { + while (_idx - start_idx < _width) { + _out(' ', _buffer, _idx++, _maxlen); + } } } - return idx; + return _idx; } -#endif /* PRINTF_SUPPORT_EXPONENTIAL */ -#endif /* PRINTF_SUPPORT_FLOAT */ +# endif /* PRINTF_SUPPORT_EXPONENTIAL */ +#endif /* PRINTF_SUPPORT_FLOAT */ // internal vsnprintf -int _vsnprintf(char *buffer, const size_t maxlen, const char *format, - va_list va) { +int _vsnprintf(char* _buffer, const size_t _maxlen, const char* _format, + va_list _va) { out_fct_type out = _out_buffer; unsigned int flags, width, precision, n; size_t idx = 0U; - if (!buffer) { + if (!_buffer) { // use null output function out = _out_null; } - while (*format) { - // format specifier? %[flags][width][.precision][length] - if (*format != '%') { + while (*_format) { + // _format specifier? %[flags][width][.precision][length] + if (*_format != '%') { // no - out(*format, buffer, idx++, maxlen); - format++; + out(*_format, _buffer, idx++, _maxlen); + _format++; continue; } else { // yes, evaluate it - format++; + _format++; } // evaluate flags flags = 0U; do { - switch (*format) { + switch (*_format) { case '0': flags |= FLAGS_ZEROPAD; - format++; + _format++; n = 1U; break; case '-': flags |= FLAGS_LEFT; - format++; + _format++; n = 1U; break; case '+': flags |= FLAGS_PLUS; - format++; + _format++; n = 1U; break; case ' ': flags |= FLAGS_SPACE; - format++; + _format++; n = 1U; break; case '#': flags |= FLAGS_HASH; - format++; + _format++; n = 1U; break; default: @@ -630,77 +648,77 @@ int _vsnprintf(char *buffer, const size_t maxlen, const char *format, // evaluate width field width = 0U; - if (_is_digit(*format)) { - width = _atoi(&format); + if (_is_digit(*_format)) { + width = _atoi(&_format); } - else if (*format == '*') { - const int w = va_arg(va, int); + else if (*_format == '*') { + const int w = va_arg(_va, int); if (w < 0) { - flags |= FLAGS_LEFT; // reverse padding - width = (unsigned int)-w; + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; } else { width = (unsigned int)w; } - format++; + _format++; } // evaluate precision field precision = 0U; - if (*format == '.') { + if (*_format == '.') { flags |= FLAGS_PRECISION; - format++; - if (_is_digit(*format)) { - precision = _atoi(&format); + _format++; + if (_is_digit(*_format)) { + precision = _atoi(&_format); } - else if (*format == '*') { - const int prec = (int)va_arg(va, int); + else if (*_format == '*') { + const int prec = (int)va_arg(_va, int); precision = prec > 0 ? (unsigned int)prec : 0U; - format++; + _format++; } } // evaluate length field - switch (*format) { + switch (*_format) { case 'l': flags |= FLAGS_LONG; - format++; - if (*format == 'l') { + _format++; + if (*_format == 'l') { flags |= FLAGS_LONG_LONG; - format++; + _format++; } break; case 'h': flags |= FLAGS_SHORT; - format++; - if (*format == 'h') { + _format++; + if (*_format == 'h') { flags |= FLAGS_CHAR; - format++; + _format++; } break; #if defined(PRINTF_SUPPORT_PTRDIFF_T) case 't': flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; + _format++; break; #endif case 'j': flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; + _format++; break; case 'z': flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; + _format++; break; default: break; } // evaluate specifier - switch (*format) { + switch (*_format) { case 'd': case 'i': case 'u': @@ -710,26 +728,26 @@ int _vsnprintf(char *buffer, const size_t maxlen, const char *format, case 'b': { // set the base unsigned int base; - if (*format == 'x' || *format == 'X') { + if (*_format == 'x' || *_format == 'X') { base = 16U; } - else if (*format == 'o') { + else if (*_format == 'o') { base = 8U; } - else if (*format == 'b') { + else if (*_format == 'b') { base = 2U; } else { - base = 10U; - flags &= ~FLAGS_HASH; // no hash for dec format + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec _format } // uppercase - if (*format == 'X') { + if (*_format == 'X') { flags |= FLAGS_UPPERCASE; } // no plus or space flag for u, x, X, o, b - if ((*format != 'i') && (*format != 'd')) { + if ((*_format != 'i') && (*_format != 'd')) { flags &= ~(FLAGS_PLUS | FLAGS_SPACE); } @@ -739,197 +757,202 @@ int _vsnprintf(char *buffer, const size_t maxlen, const char *format, } // convert the integer - if ((*format == 'i') || (*format == 'd')) { + if ((*_format == 'i') || (*_format == 'd')) { // signed if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - const long long value = va_arg(va, long long); + const long long value = va_arg(_va, long long); idx = _ntoa_long_long( - out, buffer, idx, maxlen, - (unsigned long long)(value > 0 ? value : 0 - value), - value < 0, base, precision, width, flags); + out, _buffer, idx, _maxlen, + (unsigned long long)(value > 0 ? value : 0 - value), + value < 0, base, precision, width, flags); #endif } else if (flags & FLAGS_LONG) { - const long value = va_arg(va, long); - idx = _ntoa_long( - out, buffer, idx, maxlen, - (unsigned long)(value > 0 ? value : 0 - value), - value < 0, base, precision, width, flags); + const long value = va_arg(_va, long); + idx = _ntoa_long(out, _buffer, idx, _maxlen, + (unsigned long)(value > 0 ? value + : 0 - value), + value < 0, base, precision, width, + flags); } else { - const int value = - (flags & FLAGS_CHAR) ? (char)va_arg(va, int) - : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) - : va_arg(va, int); - idx = _ntoa_long( - out, buffer, idx, maxlen, - (unsigned int)(value > 0 ? value : 0 - value), - value < 0, base, precision, width, flags); + const int value + = (flags & FLAGS_CHAR) ? (char)va_arg(_va, int) + : (flags & FLAGS_SHORT) ? (short int)va_arg(_va, int) + : va_arg(_va, int); + idx = _ntoa_long(out, _buffer, idx, _maxlen, + (unsigned int)(value > 0 ? value + : 0 - value), + value < 0, base, precision, width, + flags); } } else { // unsigned if (flags & FLAGS_LONG_LONG) { #if defined(PRINTF_SUPPORT_LONG_LONG) - idx = _ntoa_long_long(out, buffer, idx, maxlen, - va_arg(va, unsigned long long), + idx = _ntoa_long_long(out, _buffer, idx, _maxlen, + va_arg(_va, unsigned long long), false, base, precision, width, flags); #endif } else if (flags & FLAGS_LONG) { - idx = _ntoa_long(out, buffer, idx, maxlen, - va_arg(va, unsigned long), false, base, - precision, width, flags); + idx = _ntoa_long(out, _buffer, idx, _maxlen, + va_arg(_va, unsigned long), false, + base, precision, width, flags); } else { - const unsigned int value = - (flags & FLAGS_CHAR) - ? (unsigned char)va_arg(va, unsigned int) - : (flags & FLAGS_SHORT) - ? (unsigned short int)va_arg(va, unsigned int) - : va_arg(va, unsigned int); - idx = _ntoa_long(out, buffer, idx, maxlen, value, false, - base, precision, width, flags); + const unsigned int value + = (flags & FLAGS_CHAR) + ? (unsigned char)va_arg(_va, unsigned int) + : (flags & FLAGS_SHORT) + ? (unsigned short int)va_arg(_va, unsigned int) + : va_arg(_va, unsigned int); + idx = _ntoa_long(out, _buffer, idx, _maxlen, value, + false, base, precision, width, flags); } } - format++; + _format++; break; } #if defined(PRINTF_SUPPORT_FLOAT) case 'f': case 'F': - if (*format == 'F') + if (*_format == 'F') { flags |= FLAGS_UPPERCASE; - idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), + } + idx = _ftoa(out, _buffer, idx, _maxlen, va_arg(_va, double), precision, width, flags); - format++; + _format++; break; -#if defined(PRINTF_SUPPORT_EXPONENTIAL) +# if defined(PRINTF_SUPPORT_EXPONENTIAL) case 'e': case 'E': case 'g': case 'G': - if ((*format == 'g') || (*format == 'G')) + if ((*_format == 'g') || (*_format == 'G')) { flags |= FLAGS_ADAPT_EXP; - if ((*format == 'E') || (*format == 'G')) + } + if ((*_format == 'E') || (*_format == 'G')) { flags |= FLAGS_UPPERCASE; - idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), + } + idx = _etoa(out, _buffer, idx, _maxlen, va_arg(_va, double), precision, width, flags); - format++; + _format++; break; -#endif // PRINTF_SUPPORT_EXPONENTIAL -#endif // PRINTF_SUPPORT_FLOAT +# endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT case 'c': { unsigned int l = 1U; // pre padding if (!(flags & FLAGS_LEFT)) { while (l++ < width) { - out(' ', buffer, idx++, maxlen); + out(' ', _buffer, idx++, _maxlen); } } // char output - out((char)va_arg(va, int), buffer, idx++, maxlen); + out((char)va_arg(_va, int), _buffer, idx++, _maxlen); // post padding if (flags & FLAGS_LEFT) { while (l++ < width) { - out(' ', buffer, idx++, maxlen); + out(' ', _buffer, idx++, _maxlen); } } - format++; + _format++; break; } case 's': { - const char * p = va_arg(va, char *); - unsigned int l = - _strnlen_s(p, precision ? precision : (size_t)-1); + const char* p = va_arg(_va, char*); + unsigned int l + = _strnlen_s(p, precision ? precision : (size_t)-1); // pre padding if (flags & FLAGS_PRECISION) { l = (l < precision ? l : precision); } if (!(flags & FLAGS_LEFT)) { while (l++ < width) { - out(' ', buffer, idx++, maxlen); + out(' ', _buffer, idx++, _maxlen); } } // string output - while ((*p != 0) && - (!(flags & FLAGS_PRECISION) || precision--)) { - out(*(p++), buffer, idx++, maxlen); + while ((*p != 0) + && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), _buffer, idx++, _maxlen); } // post padding if (flags & FLAGS_LEFT) { while (l++ < width) { - out(' ', buffer, idx++, maxlen); + out(' ', _buffer, idx++, _maxlen); } } - format++; + _format++; break; } case 'p': { - width = sizeof(void *) * 2U; + width = sizeof(void*) * 2U; flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; #if defined(PRINTF_SUPPORT_LONG_LONG) const bool is_ll = sizeof(uintptr_t) == sizeof(long long); if (is_ll) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, - (unsigned long)va_arg(va, void *), + idx = _ntoa_long_long(out, _buffer, idx, _maxlen, + (unsigned long)va_arg(_va, void*), false, 16U, precision, width, flags); } else { #endif idx = _ntoa_long( - out, buffer, idx, maxlen, - (unsigned long)((unsigned long)va_arg(va, void *)), - false, 16U, precision, width, flags); + out, _buffer, idx, _maxlen, + (unsigned long)((unsigned long)va_arg(_va, void*)), false, + 16U, precision, width, flags); #if defined(PRINTF_SUPPORT_LONG_LONG) } #endif - format++; + _format++; break; } case '%': - out('%', buffer, idx++, maxlen); - format++; + out('%', _buffer, idx++, _maxlen); + _format++; break; default: - out(*format, buffer, idx++, maxlen); - format++; + out(*_format, _buffer, idx++, _maxlen); + _format++; break; } } // termination - out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + out((char)0, _buffer, idx < _maxlen ? idx : _maxlen - 1U, _maxlen); // return written chars without terminating \0 return (int)idx; } -int sprintf_(char *buffer, const char *format, ...) { +int sprintf_(char* _buffer, const char* _format, ...) { va_list va; - va_start(va, format); - // const int ret = _vsnprintf(buffer, (size_t)-1, format, va); - const int ret = _vsnprintf(buffer, (size_t)-1, "TEST:%d\n", va); + va_start(va, _format); + // const int ret = _vsnprintf(_buffer, (size_t)-1, _format, va); + const int ret = _vsnprintf(_buffer, (size_t)-1, "TEST:%d\n", va); va_end(va); return ret; } -int snprintf_(char *buffer, size_t count, const char *format, ...) { +int snprintf_(char* _buffer, size_t _count, const char* _format, ...) { va_list va; - va_start(va, format); - const int ret = _vsnprintf(buffer, count, format, va); + va_start(va, _format); + const int ret = _vsnprintf(_buffer, _count, _format, va); va_end(va); return ret; } -int vsnprintf_(char *buffer, size_t count, const char *format, va_list va) { - return _vsnprintf(buffer, count, format, va); +int vsnprintf_(char* _buffer, size_t _count, const char* _format, va_list _va) { + return _vsnprintf(_buffer, _count, _format, _va); } #ifdef __cplusplus diff --git a/src/libc/src/stdlib/atoi.c b/src/libc/src/stdlib/atoi.c index 3e46a36c5..1c97acaa2 100644 --- a/src/libc/src/stdlib/atoi.c +++ b/src/libc/src/stdlib/atoi.c @@ -1,8 +1,18 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// atoi.c for Simple-XX/SimpleKernel. +/** + * @file atoi.c + * @brief atoi 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ #include "stddef.h" #include "stdlib.h" @@ -11,14 +21,14 @@ int abs(int _i) { return _i < 0 ? -_i : _i; } -int atoi(const char *_str) { - return (int)strtol(_str, (char **)NULL, 10); +int atoi(const char* _str) { + return (int)strtol(_str, (char**)NULL, 10); } -long atol(const char *_str) { - return (long)strtoll(_str, (char **)NULL, 10); +long atol(const char* _str) { + return (long)strtoll(_str, (char**)NULL, 10); } -long long atoll(const char *_str) { - return (long long)strtoll(_str, (char **)NULL, 10); +long long atoll(const char* _str) { + return (long long)strtoll(_str, (char**)NULL, 10); } diff --git a/src/libc/src/stdlib/itoa.c b/src/libc/src/stdlib/itoa.c index 5c2717246..8d3517e43 100644 --- a/src/libc/src/stdlib/itoa.c +++ b/src/libc/src/stdlib/itoa.c @@ -1,33 +1,43 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// itoa.c for Simple-XX/SimpleKernel. +/** + * @file itoa.c + * @brief itoa 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ #include "stdlib.h" #include "string.h" -int itoa(int num, char *str, int len, int base) { - int sum = num; +int itoa(int _num, char* _str, int _len, int _base) { + int sum = _num; int i = 0; int digit; - if (len == 0) { + if (_len == 0) { return -1; } do { - digit = sum % base; + digit = sum % _base; if (digit < 0xA) { - str[i++] = '0' + digit; + _str[i++] = '0' + digit; } else { - str[i++] = 'A' + digit - 0xA; + _str[i++] = 'A' + digit - 0xA; } - sum /= base; - } while (sum && (i < (len - 1))); - if (i == (len - 1) && sum) { + sum /= _base; + } while (sum && (i < (_len - 1))); + if (i == (_len - 1) && sum) { return -1; } - str[i] = '\0'; - strrev(str); + _str[i] = '\0'; + strrev(_str); return 0; } diff --git a/src/libc/src/stdlib/strtol.c b/src/libc/src/stdlib/strtol.c index dacaa82ab..d73a20c71 100644 --- a/src/libc/src/stdlib/strtol.c +++ b/src/libc/src/stdlib/strtol.c @@ -1,13 +1,24 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on libgcc -// strtol.c for Simple-XX/SimpleKernel. +/** + * @file strtol.c + * @brief strtol 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on libgcc + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ -#include "stdlib.h" #include "ctype.h" #include "limits.h" #include "math.h" +#include "stdlib.h" /* * Convert a string to a long integer. @@ -15,8 +26,8 @@ * Ignores `locale' stuff. Assumes that the upper and lower case * alphabets and digits are each contiguous. */ -long strtol(const char *nptr, char **endptr, int base) { - const char * s = nptr; +long strtol(const char* _nptr, char** _endptr, int _base) { + const char* s = _nptr; unsigned long acc; int c; unsigned long cutoff; @@ -34,15 +45,17 @@ long strtol(const char *nptr, char **endptr, int base) { neg = 1; c = *s++; } - else if (c == '+') + else if (c == '+') { c = *s++; - if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; } - if (base == 0) - base = c == '0' ? 8 : 10; + if ((_base == 0 || _base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + _base = 16; + } + if (_base == 0) { + _base = c == '0' ? 8 : 10; + } /* * Compute the cutoff value between legal numbers and illegal @@ -61,33 +74,40 @@ long strtol(const char *nptr, char **endptr, int base) { * Set any if any `digits' consumed; make it negative to indicate * overflow. */ - cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; - cutlim = cutoff % (unsigned long)base; - cutoff /= (unsigned long)base; + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)_base; + cutoff /= (unsigned long)_base; for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) + if (isdigit(c)) { c -= '0'; - else if (isalpha(c)) + } + else if (isalpha(c)) { c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else + } + else { break; - if (c >= base) + } + if (c >= _base) { break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + } + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) { any = -1; + } else { - any = 1; - acc *= base; + any = 1; + acc *= _base; acc += c; } } if (any < 0) { acc = neg ? LONG_MIN : LONG_MAX; } - else if (neg) + else if (neg) { acc = -acc; - if (endptr != 0) - *endptr = (char *)(any ? s - 1 : nptr); + } + if (_endptr != 0) { + *_endptr = (char*)(any ? s - 1 : _nptr); + } return (acc); } @@ -97,8 +117,8 @@ long strtol(const char *nptr, char **endptr, int base) { * Ignores `locale' stuff. Assumes that the upper and lower case * alphabets and digits are each contiguous. */ -long long strtoll(const char *nptr, char **endptr, int base) { - const char *s = nptr; +long long strtoll(const char* _nptr, char** _endptr, int _base) { + const char* s = _nptr; long long acc; int c; long long cutoff; @@ -115,15 +135,17 @@ long long strtoll(const char *nptr, char **endptr, int base) { neg = 1; c = *s++; } - else if (c == '+') + else if (c == '+') { c = *s++; - if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; } - if (base == 0) - base = c == '0' ? 8 : 10; + if ((_base == 0 || _base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + _base = 16; + } + if (_base == 0) { + _base = c == '0' ? 8 : 10; + } /* * Compute the cutoff value between legal numbers and illegal * numbers. That is the largest legal value, divided by the @@ -145,34 +167,41 @@ long long strtoll(const char *nptr, char **endptr, int base) { : LLONG_MAX; #if defined(__i386__) - cutoff = udivmoddi4(cutoff, base, (unsigned long long *)&cutlim); + cutoff = udivmoddi4(cutoff, _base, (unsigned long long*)&cutlim); #else - cutlim = cutoff % (long long)base; - cutoff /= (long long)base; + cutlim = cutoff % (long long)_base; + cutoff /= (long long)_base; #endif for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) + if (isdigit(c)) { c -= '0'; - else if (isalpha(c)) + } + else if (isalpha(c)) { c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else + } + else { break; - if (c >= base) + } + if (c >= _base) { break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + } + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) { any = -1; + } else { - any = 1; - acc *= base; + any = 1; + acc *= _base; acc += c; } } if (any < 0) { acc = neg ? LLONG_MIN : LLONG_MAX; } - else if (neg) + else if (neg) { acc = -acc; - if (endptr != 0) - *endptr = (char *)(any ? s - 1 : nptr); + } + if (_endptr != 0) { + *_endptr = (char*)(any ? s - 1 : _nptr); + } return (acc); } diff --git a/src/libc/src/string/string.c b/src/libc/src/string/string.c index 22a49bd98..aa60e4db0 100644 --- a/src/libc/src/string/string.c +++ b/src/libc/src/string/string.c @@ -1,55 +1,69 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// string.c for Simple-XX/SimpleKernel. +/** + * @file string.c + * @brief string 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ #ifdef __cplusplus extern "C" { #endif -#include "stddef.h" #include "string.h" #include "assert.h" +#include "stddef.h" #define __glibc_unlikely(cond) __builtin_expect((cond), 0) -#define __glibc_likely(cond) __builtin_expect((cond), 1) +#define __glibc_likely(cond) __builtin_expect((cond), 1) // 获取字符串长度 -size_t strlen(const char *str) { +size_t strlen(const char* _str) { size_t len = 0; - while (str[len]) { + while (_str[len]) { len++; } return len; } -size_t strnlen(const char *str, size_t maxlen) { - const char * char_ptr, *end_ptr = str + maxlen; - const unsigned long int *longword_ptr; +size_t strnlen(const char* _str, size_t _maxlen) { + const char * char_ptr, *end_ptr = _str + _maxlen; + const unsigned long int* longword_ptr; unsigned long int longword, himagic, lomagic; - if (maxlen == 0) + if (_maxlen == 0) { return 0; + } - if (__glibc_unlikely(end_ptr < str)) - end_ptr = (const char *)~0UL; + if (__glibc_unlikely(end_ptr < _str)) { + end_ptr = (const char*)~0UL; + } /* Handle the first few characters by reading one character at a time. Do this until CHAR_PTR is aligned on a longword boundary. */ - for (char_ptr = str; + for (char_ptr = _str; ((unsigned long int)char_ptr & (sizeof(longword) - 1)) != 0; - ++char_ptr) + ++char_ptr) { if (*char_ptr == '\0') { - if (char_ptr > end_ptr) + if (char_ptr > end_ptr) { char_ptr = end_ptr; - return char_ptr - str; + } + return char_ptr - _str; } + } /* All these elucidatory comments refer to 4-byte longwords, but the theory applies equally well to 8-byte longwords. */ - longword_ptr = (unsigned long int *)char_ptr; + longword_ptr = (unsigned long int*)char_ptr; /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits the "holes." Note that there is a hole just to the left of @@ -60,8 +74,8 @@ size_t strnlen(const char *str, size_t maxlen) { The 1-bits make sure that carries propagate to the next 0-bit. The 0-bits provide holes for carries to fall into. */ - himagic = 0x80808080L; - lomagic = 0x01010101L; + himagic = 0x80808080L; + lomagic = 0x01010101L; if (sizeof(longword) > 4) { /* 64-bit version of the magic. */ /* Do the shift in two steps to avoid a warning if long has 32 bits. */ @@ -76,177 +90,196 @@ size_t strnlen(const char *str, size_t maxlen) { /* Instead of the traditional loop which tests each character, we will test a longword at a time. The tricky part is testing if *any of the four* bytes in the longword in question are zero. */ - while (longword_ptr < (unsigned long int *)end_ptr) { + while (longword_ptr < (unsigned long int*)end_ptr) { longword = *longword_ptr++; if ((longword - lomagic) & himagic) { /* Which of the bytes was the zero? If none of them were, it was a misfire; continue the search. */ - const char *cp = (const char *)(longword_ptr - 1); + const char* cp = (const char*)(longword_ptr - 1); - char_ptr = cp; - if (cp[0] == 0) + char_ptr = cp; + if (cp[0] == 0) { break; + } char_ptr = cp + 1; - if (cp[1] == 0) + if (cp[1] == 0) { break; + } char_ptr = cp + 2; - if (cp[2] == 0) + if (cp[2] == 0) { break; + } char_ptr = cp + 3; - if (cp[3] == 0) + if (cp[3] == 0) { break; + } if (sizeof(longword) > 4) { char_ptr = cp + 4; - if (cp[4] == 0) + if (cp[4] == 0) { break; + } char_ptr = cp + 5; - if (cp[5] == 0) + if (cp[5] == 0) { break; + } char_ptr = cp + 6; - if (cp[6] == 0) + if (cp[6] == 0) { break; + } char_ptr = cp + 7; - if (cp[7] == 0) + if (cp[7] == 0) { break; + } } } char_ptr = end_ptr; } - if (char_ptr > end_ptr) + if (char_ptr > end_ptr) { char_ptr = end_ptr; - return char_ptr - str; + } + return char_ptr - _str; } // 如果 src > dest, 则返回值大于 0,如果 src = dest, 则返回值等于 0, // 如果 srd < dest ,则返回值小于 0。 -int strcmp(const char *src, const char *dest) { - while (*src && *dest && (*src == *dest)) { - src++; - dest++; +int strcmp(const char* _src, const char* _dest) { + while (*_src && *_dest && (*_src == *_dest)) { + _src++; + _dest++; } - return *src - *dest; + return *_src - *_dest; } -int strncmp(const char *s1, const char *s2, size_t n) { - - if (n == 0) +int strncmp(const char* _s1, const char* _s2, size_t _n) { + if (_n == 0) { return 0; + } do { - if (*s1 != *s2++) - return (*(const unsigned char *)s1 - - *(const unsigned char *)(s2 - 1)); - if (*s1++ == '\0') + if (*_s1 != *_s2++) { + return (*(const unsigned char*)_s1 + - *(const unsigned char*)(_s2 - 1)); + } + if (*_s1++ == '\0') { break; - } while (--n != 0); + } + } while (--_n != 0); return 0; } -char *strcpy(char *dest, const char *src) { - char *address = dest; - while ((*dest++ = *src++) != '\0') { +char* strcpy(char* _dest, const char* _src) { + char* address = _dest; + while ((*_dest++ = *_src++) != '\0') { ; } return address; } -char *strncpy(char *s1, const char *s2, size_t n) { - size_t size = strnlen(s2, n); - if (size != n) - memset(s1 + size, '\0', n - size); - return memcpy(s1, s2, size); +char* strncpy(char* _s1, const char* _s2, size_t _n) { + size_t size = strnlen(_s2, _n); + if (size != _n) { + memset(_s1 + size, '\0', _n - size); + } + return memcpy(_s1, _s2, size); } -void backspace(char *src) { - size_t len = strlen(src); - src[len - 1] = '\0'; +void backspace(char* _src) { + size_t len = strlen(_src); + _src[len - 1] = '\0'; } -void append(char *src, char dest) { - size_t len = strlen(src); - src[len] = dest; - src[len + 1] = '\0'; +void append(char* _src, char _dest) { + size_t len = strlen(_src); + _src[len] = _dest; + _src[len + 1] = '\0'; } -char *strcat(char *dest, const char *src) { - uint8_t *add_d = (uint8_t *)dest; - if (dest != 0 && src != 0) { +char* strcat(char* _dest, const char* _src) { + uint8_t* add_d = (uint8_t*)_dest; + if (_dest != 0 && _src != 0) { while (*add_d) { add_d++; } - while (*src) { - *add_d++ = *src++; + while (*_src) { + *add_d++ = *_src++; } } - return dest; + return _dest; } -char *strchr(register const char *s, int c) { +char* strchr(register const char* _s, int _c) { do { - if (*s == c) { - return (char *)s; + if (*_s == _c) { + return (char*)_s; } - } while (*s++); - return (0); + } while (*_s++); + return NULL; } -void *memcpy(void *dest, const void *src, size_t len) { - char * d = dest; - const char *s = src; - while (len--) +void* memcpy(void* _dest, const void* _src, size_t _len) { + char* d = _dest; + const char* s = _src; + while (_len--) { *d++ = *s++; - return dest; + } + return _dest; } -void *memset(void *dest, int val, size_t len) { - unsigned char *ptr = dest; - while (len-- > 0) - *ptr++ = val; - return dest; +void* memset(void* _dest, int _val, size_t _len) { + unsigned char* ptr = _dest; + while (_len-- > 0) { + *ptr++ = _val; + } + return _dest; } -void bzero(void *dest, uint32_t len) { - memset(dest, 0, len); +void bzero(void* _dest, uint32_t _len) { + memset(_dest, 0, _len); } -int memcmp(const void *str1, const void *str2, size_t count) { - register const unsigned char *s1 = (const unsigned char *)str1; - register const unsigned char *s2 = (const unsigned char *)str2; +int memcmp(const void* _str1, const void* _str2, size_t _count) { + register const unsigned char* s1 = (const unsigned char*)_str1; + register const unsigned char* s2 = (const unsigned char*)_str2; - while (count-- > 0) { - if (*s1++ != *s2++) + while (_count-- > 0) { + if (*s1++ != *s2++) { return s1[-1] < s2[-1] ? -1 : 1; + } } return 0; } -void *memmove(void *dest, const void *src, size_t len) { - char * d = dest; - const char *s = src; - if (d < s) - while (len--) +void* memmove(void* _dest, const void* _src, size_t _len) { + char* d = _dest; + const char* s = _src; + if (d < s) { + while (_len--) { *d++ = *s++; + } + } else { - const char *lasts = s + (len - 1); - char * lastd = d + (len - 1); - while (len--) + const char* lasts = s + (_len - 1); + char* lastd = d + (_len - 1); + while (_len--) { *lastd-- = *lasts--; + } } - return dest; + return _dest; } -void strrev(char *str) { +void strrev(char* _str) { int i; int j; unsigned char a; - unsigned len = strlen((const char *)str); + unsigned len = strlen((const char*)_str); for (i = 0, j = len - 1; i < j; i++, j--) { - a = str[i]; - str[i] = str[j]; - str[j] = a; + a = _str[i]; + _str[i] = _str[j]; + _str[j] = a; } + return; } #ifdef __cplusplus diff --git a/src/libcxx/CMakeLists.txt b/src/libcxx/CMakeLists.txt index cc94239e9..bf3c61791 100644 --- a/src/libcxx/CMakeLists.txt +++ b/src/libcxx/CMakeLists.txt @@ -1,5 +1,6 @@ -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). # # CMakeLists.txt for Simple-XX/SimpleKernel. diff --git a/src/libcxx/include/algo b/src/libcxx/include/algo index 633b0a101..f625c4d2f 100644 --- a/src/libcxx/include/algo +++ b/src/libcxx/include/algo @@ -1,1809 +1,1944 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// algo for Simple-XX/SimpleKernel. - -#ifndef _ALGO_ -#define _ALGO_ +/** + * @file algo + * @brief stl algo 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_ALGO +#define SIMPLEKERNEL_ALGO // 这个头文件包含了 std 的一系列算法 -#include "stddef.h" -#include "time.h" #include "algobase" -#include "memory" -#include "heap_algo" #include "functional" +#include "heap_algo" +#include "memory" +#include "stddef.h" +#include "time.h" namespace mystl { - /*****************************************************************************************/ - // all_of - // 检查[first, last)内是否全部元素都满足一元操作 unary_pred 为 true - // 的情况,满足则返回 true - /*****************************************************************************************/ - template - bool all_of(InputIter first, InputIter last, UnaryPredicate unary_pred) { - for (; first != last; ++first) { - if (!unary_pred(*first)) - return false; +/*****************************************************************************************/ +// all_of +// 检查[first, last)内是否全部元素都满足一元操作 unary_pred 为 true +// 的情况,满足则返回 true +/*****************************************************************************************/ +template +bool all_of(InputIter first, InputIter last, UnaryPredicate unary_pred) { + for (; first != last; ++first) { + if (!unary_pred(*first)) { + return false; } - return true; } + return true; +} - /*****************************************************************************************/ - // any_of - // 检查[first, last)内是否存在某个元素满足一元操作 unary_pred 为 true - // 的情况,满足则返回 true - /*****************************************************************************************/ - template - bool any_of(InputIter first, InputIter last, UnaryPredicate unary_pred) { - for (; first != last; ++first) { - if (unary_pred(*first)) - return true; +/*****************************************************************************************/ +// any_of +// 检查[first, last)内是否存在某个元素满足一元操作 unary_pred 为 true +// 的情况,满足则返回 true +/*****************************************************************************************/ +template +bool any_of(InputIter first, InputIter last, UnaryPredicate unary_pred) { + for (; first != last; ++first) { + if (unary_pred(*first)) { + return true; } - return false; } + return false; +} - /*****************************************************************************************/ - // none_of - // 检查[first, last)内是否全部元素都不满足一元操作 unary_pred 为 true - // 的情况,满足则返回 true - /*****************************************************************************************/ - template - bool none_of(InputIter first, InputIter last, UnaryPredicate unary_pred) { - for (; first != last; ++first) { - if (unary_pred(*first)) - return false; +/*****************************************************************************************/ +// none_of +// 检查[first, last)内是否全部元素都不满足一元操作 unary_pred 为 true +// 的情况,满足则返回 true +/*****************************************************************************************/ +template +bool none_of(InputIter first, InputIter last, UnaryPredicate unary_pred) { + for (; first != last; ++first) { + if (unary_pred(*first)) { + return false; } - return true; } - - /*****************************************************************************************/ - // count - // 对[first, last)区间内的元素与给定值进行比较,缺省使用 - // operator==,返回元素相等的个数 - /*****************************************************************************************/ - template - size_t count(InputIter first, InputIter last, const T &value) { - size_t n = 0; - for (; first != last; ++first) { - if (*first == value) - ++n; - } - return n; - } - - /*****************************************************************************************/ - // count_if - // 对[first, last)区间内的每个元素都进行一元 unary_pred 操作,返回结果为 - // true 的个数 - /*****************************************************************************************/ - template - size_t count_if(InputIter first, InputIter last, - UnaryPredicate unary_pred) { - size_t n = 0; - for (; first != last; ++first) { - if (unary_pred(*first)) - ++n; - } - return n; - } - - /*****************************************************************************************/ - // find - // 在[first, last)区间内找到等于 value 的元素,返回指向该元素的迭代器 - /*****************************************************************************************/ - template - InputIter find(InputIter first, InputIter last, const T &value) { - while (first != last && *first != value) - ++first; - return first; + return true; +} + +/*****************************************************************************************/ +// count +// 对[first, last)区间内的元素与给定值进行比较,缺省使用 +// operator==,返回元素相等的个数 +/*****************************************************************************************/ +template +size_t count(InputIter first, InputIter last, const T& value) { + size_t n = 0; + for (; first != last; ++first) { + if (*first == value) { + ++n; + } + } + return n; +} + +/*****************************************************************************************/ +// count_if +// 对[first, last)区间内的每个元素都进行一元 unary_pred 操作,返回结果为 +// true 的个数 +/*****************************************************************************************/ +template +size_t count_if(InputIter first, InputIter last, UnaryPredicate unary_pred) { + size_t n = 0; + for (; first != last; ++first) { + if (unary_pred(*first)) { + ++n; + } + } + return n; +} + +/*****************************************************************************************/ +// find +// 在[first, last)区间内找到等于 value 的元素,返回指向该元素的迭代器 +/*****************************************************************************************/ +template +InputIter find(InputIter first, InputIter last, const T& value) { + while (first != last && *first != value) { + ++first; + } + return first; +} + +/*****************************************************************************************/ +// find_if +// 在[first, last)区间内找到第一个令一元操作 unary_pred 为 true +// 的元素并返回指向该元素的迭代器 +/*****************************************************************************************/ +template +InputIter find_if(InputIter first, InputIter last, UnaryPredicate unary_pred) { + while (first != last && !unary_pred(*first)) { + ++first; + } + return first; +} + +/*****************************************************************************************/ +// find_if_not +// 在[first, last)区间内找到第一个令一元操作 unary_pred 为 false +// 的元素并返回指向该元素的迭代器 +/*****************************************************************************************/ +template +InputIter +find_if_not(InputIter first, InputIter last, UnaryPredicate unary_pred) { + while (first != last && unary_pred(*first)) { + ++first; + } + return first; +} + +/*****************************************************************************************/ +// search +// 在[first1, last1)中查找[first2, last2)的首次出现点 +/*****************************************************************************************/ +template +ForwardIter1 search(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2) { + auto d1 = mystl::distance(first1, last1); + auto d2 = mystl::distance(first2, last2); + if (d1 < d2) { + return last1; } - - /*****************************************************************************************/ - // find_if - // 在[first, last)区间内找到第一个令一元操作 unary_pred 为 true - // 的元素并返回指向该元素的迭代器 - /*****************************************************************************************/ - template - InputIter find_if(InputIter first, InputIter last, - UnaryPredicate unary_pred) { - while (first != last && !unary_pred(*first)) - ++first; - return first; + auto current1 = first1; + auto current2 = first2; + while (current2 != last2) { + if (*current1 == *current2) { + ++current1; + ++current2; + } + else { + if (d1 == d2) { + return last1; + } + else { + current1 = ++first1; + current2 = first2; + --d1; + } + } } + return first1; +} - /*****************************************************************************************/ - // find_if_not - // 在[first, last)区间内找到第一个令一元操作 unary_pred 为 false - // 的元素并返回指向该元素的迭代器 - /*****************************************************************************************/ - template - InputIter find_if_not(InputIter first, InputIter last, - UnaryPredicate unary_pred) { - while (first != last && unary_pred(*first)) - ++first; - return first; +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter1 search(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, Compared comp) { + auto d1 = mystl::distance(first1, last1); + auto d2 = mystl::distance(first2, last2); + if (d1 < d2) { + return last1; } - - /*****************************************************************************************/ - // search - // 在[first1, last1)中查找[first2, last2)的首次出现点 - /*****************************************************************************************/ - template - ForwardIter1 search(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2) { - auto d1 = mystl::distance(first1, last1); - auto d2 = mystl::distance(first2, last2); - if (d1 < d2) - return last1; - auto current1 = first1; - auto current2 = first2; - while (current2 != last2) { - if (*current1 == *current2) { - ++current1; - ++current2; + auto current1 = first1; + auto current2 = first2; + while (current2 != last2) { + if (comp(*current1, *current2)) { + ++current1; + ++current2; + } + else { + if (d1 == d2) { + return last1; } else { - if (d1 == d2) { - return last1; - } - else { - current1 = ++first1; - current2 = first2; - --d1; - } + current1 = ++first1; + current2 = first2; + --d1; } } - return first1; } + return first1; +} - // 重载版本使用函数对象 comp 代替比较操作 - template - ForwardIter1 search(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2, - Compared comp) { - auto d1 = mystl::distance(first1, last1); - auto d2 = mystl::distance(first2, last2); - if (d1 < d2) - return last1; - auto current1 = first1; - auto current2 = first2; - while (current2 != last2) { - if (comp(*current1, *current2)) { - ++current1; - ++current2; +/*****************************************************************************************/ +// search_n +// 在[first, last)中查找连续 n 个 value +// 所形成的子序列,返回一个迭代器指向该子序列的起始处 +/*****************************************************************************************/ +template +ForwardIter +search_n(ForwardIter first, ForwardIter last, Size n, const T& value) { + if (n <= 0) { + return first; + } + else { + first = mystl::find(first, last, value); + while (first != last) { + auto m = n - 1; + auto i = first; + ++i; + while (i != last && m != 0 && *i == value) { + ++i; + --m; + } + if (m == 0) { + return first; } else { - if (d1 == d2) { - return last1; - } - else { - current1 = ++first1; - current2 = first2; - --d1; - } + first = mystl::find(i, last, value); } } - return first1; + return last; } +} - /*****************************************************************************************/ - // search_n - // 在[first, last)中查找连续 n 个 value - // 所形成的子序列,返回一个迭代器指向该子序列的起始处 - /*****************************************************************************************/ - template - ForwardIter search_n(ForwardIter first, ForwardIter last, Size n, - const T &value) { - if (n <= 0) { - return first; +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter search_n(ForwardIter first, ForwardIter last, Size n, + const T& value, Compared comp) { + if (n <= 0) { + return first; + } + else { + while (first != last) { + if (comp(*first, value)) { + break; + } + ++first; } - else { - first = mystl::find(first, last, value); - while (first != last) { - auto m = n - 1; - auto i = first; + while (first != last) { + auto m = n - 1; + auto i = first; + ++i; + while (i != last && m != 0 && comp(*i, value)) { ++i; - while (i != last && m != 0 && *i == value) { + --m; + } + if (m == 0) { + return first; + } + else { + while (i != last) { + if (comp(*i, value)) { + break; + } ++i; - --m; - } - if (m == 0) { - return first; - } - else { - first = mystl::find(i, last, value); } + first = i; } - return last; } + return last; } - - // 重载版本使用函数对象 comp 代替比较操作 - template - ForwardIter search_n(ForwardIter first, ForwardIter last, Size n, - const T &value, Compared comp) { - if (n <= 0) { - return first; - } - else { - while (first != last) { - if (comp(*first, value)) - break; - ++first; +} + +/*****************************************************************************************/ +// find_end +// 在[first1, last1)区间中查找[first2, +// last2)最后一次出现的地方,若不存在返回 last1 +/*****************************************************************************************/ +// find_end_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter1 find_end_dispatch(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, + forward_iterator_tag, forward_iterator_tag) { + if (first2 == last2) { + return last1; + } + else { + auto result = last1; + while (true) { + // 利用 search 查找某个子序列的首次出现点,找不到则返回 last1 + auto new_result = mystl::search(first1, last1, first2, last2); + if (new_result == last1) { + return result; } - while (first != last) { - auto m = n - 1; - auto i = first; - ++i; - while (i != last && m != 0 && comp(*i, value)) { - ++i; - --m; - } - if (m == 0) { - return first; - } - else { - while (i != last) { - if (comp(*i, value)) - break; - ++i; - } - first = i; - } + else { + result = new_result; + first1 = new_result; + ++first1; } - return last; } } +} - /*****************************************************************************************/ - // find_end - // 在[first1, last1)区间中查找[first2, - // last2)最后一次出现的地方,若不存在返回 last1 - /*****************************************************************************************/ - // find_end_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter1 find_end_dispatch(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2, - forward_iterator_tag, forward_iterator_tag) { - if (first2 == last2) { - return last1; - } - else { - auto result = last1; - while (true) { - // 利用 search 查找某个子序列的首次出现点,找不到则返回 last1 - auto new_result = mystl::search(first1, last1, first2, last2); - if (new_result == last1) { - return result; - } - else { - result = new_result; - first1 = new_result; - ++first1; - } +// find_end_dispatch 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter1 +find_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + bidirectional_iterator_tag, bidirectional_iterator_tag) { + typedef reverse_iterator reviter1; + typedef reverse_iterator reviter2; + reviter1 rlast1(first1); + reviter2 rlast2(first2); + reviter1 rresult + = mystl::search(reviter1(last1), rlast1, reviter2(last2), rlast2); + if (rresult == rlast1) { + return last1; + } + else { + auto result = rresult.base(); + mystl::advance(result, -mystl::distance(first2, last2)); + return result; + } +} + +template +ForwardIter1 find_end(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2) { + typedef typename iterator_traits::iterator_category Category1; + typedef typename iterator_traits::iterator_category Category2; + return mystl::find_end_dispatch(first1, last1, first2, last2, Category1(), + Category2()); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// find_end_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter1 +find_end_dispatch(ForwardIter1 first1, ForwardIter1 last1, ForwardIter2 first2, + ForwardIter2 last2, forward_iterator_tag, + forward_iterator_tag, Compared comp) { + if (first2 == last2) { + return last1; + } + else { + auto result = last1; + while (true) { + // 利用 search 查找某个子序列的首次出现点,找不到则返回 last1 + auto new_result = mystl::search(first1, last1, first2, last2, comp); + if (new_result == last1) { + return result; + } + else { + result = new_result; + first1 = new_result; + ++first1; } } } +} - // find_end_dispatch 的 bidirectional_iterator_tag 版本 - template - BidirectionalIter1 - find_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1, - BidirectionalIter2 first2, BidirectionalIter2 last2, - bidirectional_iterator_tag, bidirectional_iterator_tag) { - typedef reverse_iterator reviter1; - typedef reverse_iterator reviter2; - reviter1 rlast1(first1); - reviter2 rlast2(first2); - reviter1 rresult = - mystl::search(reviter1(last1), rlast1, reviter2(last2), rlast2); - if (rresult == rlast1) { - return last1; - } - else { - auto result = rresult.base(); - mystl::advance(result, -mystl::distance(first2, last2)); - return result; +// find_end_dispatch 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter1 +find_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + bidirectional_iterator_tag, bidirectional_iterator_tag, + Compared comp) { + typedef reverse_iterator reviter1; + typedef reverse_iterator reviter2; + reviter1 rlast1(first1); + reviter2 rlast2(first2); + reviter1 rresult + = mystl::search(reviter1(last1), rlast1, reviter2(last2), rlast2, comp); + if (rresult == rlast1) { + return last1; + } + else { + auto result = rresult.base(); + mystl::advance(result, -mystl::distance(first2, last2)); + return result; + } +} + +template +ForwardIter1 find_end(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, Compared comp) { + typedef typename iterator_traits::iterator_category Category1; + typedef typename iterator_traits::iterator_category Category2; + return mystl::find_end_dispatch(first1, last1, first2, last2, Category1(), + Category2(), comp); +} + +/*****************************************************************************************/ +// find_first_of +// 在[first1, last1)中查找[first2, +// last2)中的某些元素,返回指向第一次出现的元素的迭代器 +/*****************************************************************************************/ +template +InputIter find_first_of(InputIter first1, InputIter last1, ForwardIter first2, + ForwardIter last2) { + for (; first1 != last1; ++first1) { + for (auto iter = first2; iter != last2; ++iter) { + if (*first1 == *iter) { + return first1; + } + } + } + return last1; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +InputIter find_first_of(InputIter first1, InputIter last1, ForwardIter first2, + ForwardIter last2, Compared comp) { + for (; first1 != last1; ++first1) { + for (auto iter = first2; iter != last2; ++iter) { + if (comp(*first1, *iter)) { + return first1; + } + } + } + return last1; +} + +/*****************************************************************************************/ +// for_each +// 使用一个函数对象 f 对[first, last)区间内的每个元素执行一个 operator() +// 操作,但不能改变元素内容 f() 可返回一个值,但该值会被忽略 +/*****************************************************************************************/ +template +Function for_each(InputIter first, InputIter last, Function f) { + for (; first != last; ++first) { + f(*first); + } + return f; +} + +/*****************************************************************************************/ +// adjacent_find +// 找出第一对匹配的相邻元素,缺省使用 operator== +// 比较,如果找到返回一个迭代器,指向这对元素的第一个元素 +/*****************************************************************************************/ +template +ForwardIter adjacent_find(ForwardIter first, ForwardIter last) { + if (first == last) { + return last; + } + auto next = first; + while (++next != last) { + if (*first == *next) { + return first; } + first = next; } + return last; +} - template - ForwardIter1 find_end(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2) { - typedef - typename iterator_traits::iterator_category Category1; - typedef - typename iterator_traits::iterator_category Category2; - return mystl::find_end_dispatch(first1, last1, first2, last2, - Category1(), Category2()); +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter adjacent_find(ForwardIter first, ForwardIter last, Compared comp) { + if (first == last) { + return last; } - - // 重载版本使用函数对象 comp 代替比较操作 - // find_end_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter1 find_end_dispatch(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2, - forward_iterator_tag, forward_iterator_tag, - Compared comp) { - if (first2 == last2) { - return last1; + auto next = first; + while (++next != last) { + if (comp(*first, *next)) { + return first; } - else { - auto result = last1; - while (true) { - // 利用 search 查找某个子序列的首次出现点,找不到则返回 last1 - auto new_result = - mystl::search(first1, last1, first2, last2, comp); - if (new_result == last1) { - return result; - } - else { - result = new_result; - first1 = new_result; - ++first1; - } - } + first = next; + } + return last; +} + +/*****************************************************************************************/ +// lower_bound +// 在[first, last)中查找第一个不小于 value +// 的元素,并返回指向它的迭代器,若没有则返回 last +/*****************************************************************************************/ +// lbound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter lbound_dispatch(ForwardIter first, ForwardIter last, const T& value, + forward_iterator_tag) { + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (*middle < value) { + first = middle; + ++first; + len = len - half - 1; } - } - - // find_end_dispatch 的 bidirectional_iterator_tag 版本 - template - BidirectionalIter1 - find_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1, - BidirectionalIter2 first2, BidirectionalIter2 last2, - bidirectional_iterator_tag, bidirectional_iterator_tag, - Compared comp) { - typedef reverse_iterator reviter1; - typedef reverse_iterator reviter2; - reviter1 rlast1(first1); - reviter2 rlast2(first2); - reviter1 rresult = mystl::search(reviter1(last1), rlast1, - reviter2(last2), rlast2, comp); - if (rresult == rlast1) { - return last1; + else { + len = half; + } + } + return first; +} + +// lbound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter lbound_dispatch(RandomIter first, RandomIter last, const T& value, + random_access_iterator_tag) { + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) { + half = len >> 1; + middle = first + half; + if (*middle < value) { + first = middle + 1; + len = len - half - 1; } else { - auto result = rresult.base(); - mystl::advance(result, -mystl::distance(first2, last2)); - return result; + len = half; + } + } + return first; +} + +template +ForwardIter lower_bound(ForwardIter first, ForwardIter last, const T& value) { + return mystl::lbound_dispatch(first, last, value, iterator_category(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// lbound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter lbound_dispatch(ForwardIter first, ForwardIter last, const T& value, + forward_iterator_tag, Compared comp) { + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (comp(*middle, value)) { + first = middle; + ++first; + len = len - half - 1; } - } - - template - ForwardIter1 find_end(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2, - Compared comp) { - typedef - typename iterator_traits::iterator_category Category1; - typedef - typename iterator_traits::iterator_category Category2; - return mystl::find_end_dispatch(first1, last1, first2, last2, - Category1(), Category2(), comp); - } - - /*****************************************************************************************/ - // find_first_of - // 在[first1, last1)中查找[first2, - // last2)中的某些元素,返回指向第一次出现的元素的迭代器 - /*****************************************************************************************/ - template - InputIter find_first_of(InputIter first1, InputIter last1, - ForwardIter first2, ForwardIter last2) { - for (; first1 != last1; ++first1) { - for (auto iter = first2; iter != last2; ++iter) { - if (*first1 == *iter) - return first1; - } + else { + len = half; + } + } + return first; +} + +// lbound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter lbound_dispatch(RandomIter first, RandomIter last, const T& value, + random_access_iterator_tag, Compared comp) { + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) { + half = len >> 1; + middle = first + half; + if (comp(*middle, value)) { + first = middle + 1; + len = len - half - 1; } - return last1; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - InputIter find_first_of(InputIter first1, InputIter last1, - ForwardIter first2, ForwardIter last2, - Compared comp) { - for (; first1 != last1; ++first1) { - for (auto iter = first2; iter != last2; ++iter) { - if (comp(*first1, *iter)) - return first1; - } + else { + len = half; } - return last1; } + return first; +} - /*****************************************************************************************/ - // for_each - // 使用一个函数对象 f 对[first, last)区间内的每个元素执行一个 operator() - // 操作,但不能改变元素内容 f() 可返回一个值,但该值会被忽略 - /*****************************************************************************************/ - template - Function for_each(InputIter first, InputIter last, Function f) { - for (; first != last; ++first) { - f(*first); - } - return f; - } - - /*****************************************************************************************/ - // adjacent_find - // 找出第一对匹配的相邻元素,缺省使用 operator== - // 比较,如果找到返回一个迭代器,指向这对元素的第一个元素 - /*****************************************************************************************/ - template - ForwardIter adjacent_find(ForwardIter first, ForwardIter last) { - if (first == last) - return last; - auto next = first; - while (++next != last) { - if (*first == *next) - return first; - first = next; +template +ForwardIter lower_bound(ForwardIter first, ForwardIter last, const T& value, + Compared comp) { + return mystl::lbound_dispatch(first, last, value, iterator_category(first), + comp); +} + +/*****************************************************************************************/ +// upper_bound +// 在[first, last)中查找第一个大于value +// 的元素,并返回指向它的迭代器,若没有则返回 last +/*****************************************************************************************/ +// ubound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter ubound_dispatch(ForwardIter first, ForwardIter last, const T& value, + forward_iterator_tag) { + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (value < *middle) { + len = half; } - return last; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - ForwardIter adjacent_find(ForwardIter first, ForwardIter last, - Compared comp) { - if (first == last) - return last; - auto next = first; - while (++next != last) { - if (comp(*first, *next)) - return first; - first = next; + else { + first = middle; + ++first; + len = len - half - 1; } - return last; } + return first; +} - /*****************************************************************************************/ - // lower_bound - // 在[first, last)中查找第一个不小于 value - // 的元素,并返回指向它的迭代器,若没有则返回 last - /*****************************************************************************************/ - // lbound_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter lbound_dispatch(ForwardIter first, ForwardIter last, - const T &value, forward_iterator_tag) { - auto len = mystl::distance(first, last); - auto half = len; - ForwardIter middle; - while (len > 0) { - half = len >> 1; - middle = first; - mystl::advance(middle, half); - if (*middle < value) { - first = middle; - ++first; - len = len - half - 1; - } - else { - len = half; - } +// ubound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter ubound_dispatch(RandomIter first, RandomIter last, const T& value, + random_access_iterator_tag) { + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) { + half = len >> 1; + middle = first + half; + if (value < *middle) { + len = half; } - return first; - } - - // lbound_dispatch 的 random_access_iterator_tag 版本 - template - RandomIter lbound_dispatch(RandomIter first, RandomIter last, - const T &value, random_access_iterator_tag) { - auto len = last - first; - auto half = len; - RandomIter middle; - while (len > 0) { - half = len >> 1; - middle = first + half; - if (*middle < value) { - first = middle + 1; - len = len - half - 1; - } - else { - len = half; - } + else { + first = middle + 1; + len = len - half - 1; + } + } + return first; +} + +template +ForwardIter upper_bound(ForwardIter first, ForwardIter last, const T& value) { + return mystl::ubound_dispatch(first, last, value, iterator_category(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// ubound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter ubound_dispatch(ForwardIter first, ForwardIter last, const T& value, + forward_iterator_tag, Compared comp) { + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (comp(value, *middle)) { + len = half; } - return first; - } - - template - ForwardIter lower_bound(ForwardIter first, ForwardIter last, - const T &value) { - return mystl::lbound_dispatch(first, last, value, - iterator_category(first)); - } - - // 重载版本使用函数对象 comp 代替比较操作 - // lbound_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter lbound_dispatch(ForwardIter first, ForwardIter last, - const T &value, forward_iterator_tag, - Compared comp) { - auto len = mystl::distance(first, last); - auto half = len; - ForwardIter middle; - while (len > 0) { - half = len >> 1; - middle = first; - mystl::advance(middle, half); - if (comp(*middle, value)) { - first = middle; - ++first; - len = len - half - 1; - } - else { - len = half; - } + else { + first = middle; + ++first; + len = len - half - 1; } - return first; } + return first; +} - // lbound_dispatch 的 random_access_iterator_tag 版本 - template - RandomIter lbound_dispatch(RandomIter first, RandomIter last, - const T &value, random_access_iterator_tag, - Compared comp) { - auto len = last - first; - auto half = len; - RandomIter middle; - while (len > 0) { - half = len >> 1; - middle = first + half; - if (comp(*middle, value)) { - first = middle + 1; - len = len - half - 1; - } - else { - len = half; - } +// ubound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter ubound_dispatch(RandomIter first, RandomIter last, const T& value, + random_access_iterator_tag, Compared comp) { + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) { + half = len >> 1; + middle = first + half; + if (comp(value, *middle)) { + len = half; } - return first; - } - - template - ForwardIter lower_bound(ForwardIter first, ForwardIter last, const T &value, - Compared comp) { - return mystl::lbound_dispatch(first, last, value, - iterator_category(first), comp); - } - - /*****************************************************************************************/ - // upper_bound - // 在[first, last)中查找第一个大于value - // 的元素,并返回指向它的迭代器,若没有则返回 last - /*****************************************************************************************/ - // ubound_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter ubound_dispatch(ForwardIter first, ForwardIter last, - const T &value, forward_iterator_tag) { - auto len = mystl::distance(first, last); - auto half = len; - ForwardIter middle; - while (len > 0) { - half = len >> 1; - middle = first; - mystl::advance(middle, half); - if (value < *middle) { - len = half; - } - else { - first = middle; - ++first; - len = len - half - 1; - } + else { + first = middle + 1; + len = len - half - 1; } - return first; } + return first; +} - // ubound_dispatch 的 random_access_iterator_tag 版本 - template - RandomIter ubound_dispatch(RandomIter first, RandomIter last, - const T &value, random_access_iterator_tag) { - auto len = last - first; - auto half = len; - RandomIter middle; - while (len > 0) { - half = len >> 1; - middle = first + half; - if (value < *middle) { - len = half; - } - else { - first = middle + 1; - len = len - half - 1; - } +template +ForwardIter upper_bound(ForwardIter first, ForwardIter last, const T& value, + Compared comp) { + return mystl::ubound_dispatch(first, last, value, iterator_category(first), + comp); +} + +/*****************************************************************************************/ +// binary_search +// 二分查找,如果在[first, last)内有等同于 value 的元素,返回 true,否则返回 +// false +/*****************************************************************************************/ +template +bool binary_search(ForwardIter first, ForwardIter last, const T& value) { + auto i = mystl::lower_bound(first, last, value); + return i != last && !(value < *i); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool binary_search(ForwardIter first, ForwardIter last, const T& value, + Compared comp) { + auto i = mystl::lower_bound(first, last, value); + return i != last && !comp(value, *i); +} + +/*****************************************************************************************/ +// equal_range +// 查找[first,last)区间中与 value +// 相等的元素所形成的区间,返回一对迭代器指向区间首尾 +// 第一个迭代器指向第一个不小于 value 的元素,第二个迭代器指向第一个大于 +// value 的元素 +/*****************************************************************************************/ +// erange_dispatch 的 forward_iterator_tag 版本 +template +mystl::pair +erange_dispatch(ForwardIter first, ForwardIter last, const T& value, + forward_iterator_tag) { + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle, left, right; + while (len > 0) { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (*middle < value) { + first = middle; + ++first; + len = len - half - 1; } - return first; - } - - template - ForwardIter upper_bound(ForwardIter first, ForwardIter last, - const T &value) { - return mystl::ubound_dispatch(first, last, value, - iterator_category(first)); - } - - // 重载版本使用函数对象 comp 代替比较操作 - // ubound_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter ubound_dispatch(ForwardIter first, ForwardIter last, - const T &value, forward_iterator_tag, - Compared comp) { - auto len = mystl::distance(first, last); - auto half = len; - ForwardIter middle; - while (len > 0) { - half = len >> 1; - middle = first; - mystl::advance(middle, half); - if (comp(value, *middle)) { - len = half; - } - else { - first = middle; - ++first; - len = len - half - 1; - } + else if (value < *middle) { + len = half; } - return first; - } - - // ubound_dispatch 的 random_access_iterator_tag 版本 - template - RandomIter ubound_dispatch(RandomIter first, RandomIter last, - const T &value, random_access_iterator_tag, - Compared comp) { - auto len = last - first; - auto half = len; - RandomIter middle; - while (len > 0) { - half = len >> 1; - middle = first + half; - if (comp(value, *middle)) { - len = half; - } - else { - first = middle + 1; - len = len - half - 1; - } + else { + left = mystl::lower_bound(first, last, value); + mystl::advance(first, len); + right = mystl::upper_bound(++middle, first, value); + return mystl::pair(left, right); + } + } + return mystl::pair(last, last); +} + +// erange_dispatch 的 random_access_iterator_tag 版本 +template +mystl::pair +erange_dispatch(RandomIter first, RandomIter last, const T& value, + random_access_iterator_tag) { + auto len = last - first; + auto half = len; + RandomIter middle, left, right; + while (len > 0) { + half = len >> 1; + middle = first + half; + if (*middle < value) { + first = middle + 1; + len = len - half - 1; + } + else if (value < *middle) { + len = half; } - return first; - } - - template - ForwardIter upper_bound(ForwardIter first, ForwardIter last, const T &value, - Compared comp) { - return mystl::ubound_dispatch(first, last, value, - iterator_category(first), comp); - } - - /*****************************************************************************************/ - // binary_search - // 二分查找,如果在[first, last)内有等同于 value 的元素,返回 true,否则返回 - // false - /*****************************************************************************************/ - template - bool binary_search(ForwardIter first, ForwardIter last, const T &value) { - auto i = mystl::lower_bound(first, last, value); - return i != last && !(value < *i); - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - bool binary_search(ForwardIter first, ForwardIter last, const T &value, - Compared comp) { - auto i = mystl::lower_bound(first, last, value); - return i != last && !comp(value, *i); - } - - /*****************************************************************************************/ - // equal_range - // 查找[first,last)区间中与 value - // 相等的元素所形成的区间,返回一对迭代器指向区间首尾 - // 第一个迭代器指向第一个不小于 value 的元素,第二个迭代器指向第一个大于 - // value 的元素 - /*****************************************************************************************/ - // erange_dispatch 的 forward_iterator_tag 版本 - template - mystl::pair - erange_dispatch(ForwardIter first, ForwardIter last, const T &value, - forward_iterator_tag) { - auto len = mystl::distance(first, last); - auto half = len; - ForwardIter middle, left, right; - while (len > 0) { - half = len >> 1; - middle = first; - mystl::advance(middle, half); - if (*middle < value) { - first = middle; - ++first; - len = len - half - 1; - } - else if (value < *middle) { - len = half; - } - else { - left = mystl::lower_bound(first, last, value); - mystl::advance(first, len); - right = mystl::upper_bound(++middle, first, value); - return mystl::pair(left, right); - } + else { + left = mystl::lower_bound(first, middle, value); + right = mystl::upper_bound(++middle, first + len, value); + return mystl::pair(left, right); + } + } + return mystl::pair(last, last); +} + +template +mystl::pair +equal_range(ForwardIter first, ForwardIter last, const T& value) { + return mystl::erange_dispatch(first, last, value, iterator_category(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// erange_dispatch 的 forward iterator 版本 +template +mystl::pair +erange_dispatch(ForwardIter first, ForwardIter last, const T& value, + forward_iterator_tag, Compared comp) { + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle, left, right; + while (len > 0) { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (comp(*middle, value)) { + first = middle; + ++first; + len = len - half - 1; } - return mystl::pair(last, last); - } - - // erange_dispatch 的 random_access_iterator_tag 版本 - template - mystl::pair - erange_dispatch(RandomIter first, RandomIter last, const T &value, - random_access_iterator_tag) { - auto len = last - first; - auto half = len; - RandomIter middle, left, right; - while (len > 0) { - half = len >> 1; - middle = first + half; - if (*middle < value) { - first = middle + 1; - len = len - half - 1; - } - else if (value < *middle) { - len = half; - } - else { - left = mystl::lower_bound(first, middle, value); - right = mystl::upper_bound(++middle, first + len, value); - return mystl::pair(left, right); - } + else if (comp(value, *middle)) { + len = half; } - return mystl::pair(last, last); - } - - template - mystl::pair - equal_range(ForwardIter first, ForwardIter last, const T &value) { - return mystl::erange_dispatch(first, last, value, - iterator_category(first)); - } - - // 重载版本使用函数对象 comp 代替比较操作 - // erange_dispatch 的 forward iterator 版本 - template - mystl::pair - erange_dispatch(ForwardIter first, ForwardIter last, const T &value, - forward_iterator_tag, Compared comp) { - auto len = mystl::distance(first, last); - auto half = len; - ForwardIter middle, left, right; - while (len > 0) { - half = len >> 1; - middle = first; - mystl::advance(middle, half); - if (comp(*middle, value)) { - first = middle; - ++first; - len = len - half - 1; - } - else if (comp(value, *middle)) { - len = half; - } - else { - left = mystl::lower_bound(first, last, value, comp); - mystl::advance(first, len); - right = mystl::upper_bound(++middle, first, value, comp); - return mystl::pair(left, right); - } + else { + left = mystl::lower_bound(first, last, value, comp); + mystl::advance(first, len); + right = mystl::upper_bound(++middle, first, value, comp); + return mystl::pair(left, right); + } + } + return mystl::pair(last, last); +} + +// erange_dispatch 的 random access iterator 版本 +template +mystl::pair +erange_dispatch(RandomIter first, RandomIter last, const T& value, + random_access_iterator_tag, Compared comp) { + auto len = last - first; + auto half = len; + RandomIter middle, left, right; + while (len > 0) { + half = len >> 1; + middle = first + half; + if (comp(*middle, value)) { + first = middle + 1; + len = len - half - 1; + } + else if (comp(value, *middle)) { + len = half; } - return mystl::pair(last, last); - } - - // erange_dispatch 的 random access iterator 版本 - template - mystl::pair - erange_dispatch(RandomIter first, RandomIter last, const T &value, - random_access_iterator_tag, Compared comp) { - auto len = last - first; - auto half = len; - RandomIter middle, left, right; - while (len > 0) { - half = len >> 1; - middle = first + half; - if (comp(*middle, value)) { - first = middle + 1; - len = len - half - 1; - } - else if (comp(value, *middle)) { - len = half; - } - else { - left = mystl::lower_bound(first, middle, value, comp); - right = mystl::upper_bound(++middle, first + len, value, comp); - return mystl::pair(left, right); - } + else { + left = mystl::lower_bound(first, middle, value, comp); + right = mystl::upper_bound(++middle, first + len, value, comp); + return mystl::pair(left, right); } - return mystl::pair(last, last); - } - - template - mystl::pair - equal_range(ForwardIter first, ForwardIter last, const T &value, - Compared comp) { - return mystl::erange_dispatch(first, last, value, - iterator_category(first), comp); } + return mystl::pair(last, last); +} - /*****************************************************************************************/ - // generate - // 将函数对象 gen 的运算结果对[first, last)内的每个元素赋值 - /*****************************************************************************************/ - template - void generate(ForwardIter first, ForwardIter last, Generator gen) { - for (; first != last; ++first) { - *first = gen(); +template +mystl::pair +equal_range(ForwardIter first, ForwardIter last, const T& value, + Compared comp) { + return mystl::erange_dispatch(first, last, value, iterator_category(first), + comp); +} + +/*****************************************************************************************/ +// generate +// 将函数对象 gen 的运算结果对[first, last)内的每个元素赋值 +/*****************************************************************************************/ +template +void generate(ForwardIter first, ForwardIter last, Generator gen) { + for (; first != last; ++first) { + *first = gen(); + } +} + +/*****************************************************************************************/ +// generate_n +// 用函数对象 gen 连续对 n 个元素赋值 +/*****************************************************************************************/ +template +void generate_n(ForwardIter first, Size n, Generator gen) { + for (; n > 0; --n, ++first) { + *first = gen(); + } +} + +/*****************************************************************************************/ +// includes +// 判断序列一S1 是否包含序列二S2 +/*****************************************************************************************/ +template +bool includes(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2) { + while (first1 != last1 && first2 != last2) { + if (*first2 < *first1) { + return false; } - } - - /*****************************************************************************************/ - // generate_n - // 用函数对象 gen 连续对 n 个元素赋值 - /*****************************************************************************************/ - template - void generate_n(ForwardIter first, Size n, Generator gen) { - for (; n > 0; --n, ++first) { - *first = gen(); + else if (*first1 < *first2) { + ++first1; + } + else { + ++first1, ++first2; } } + return first2 == last2; +} - /*****************************************************************************************/ - // includes - // 判断序列一S1 是否包含序列二S2 - /*****************************************************************************************/ - template - bool includes(InputIter1 first1, InputIter1 last1, InputIter2 first2, - InputIter2 last2) { - while (first1 != last1 && first2 != last2) { - if (*first2 < *first1) { - return false; - } - else if (*first1 < *first2) { - ++first1; - } - else { - ++first1, ++first2; - } +// 重载版本使用函数对象 comp 代替比较操作 +template +bool includes(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, Compared comp) { + while (first1 != last1 && first2 != last2) { + if (comp(*first2, *first1)) { + return false; + } + else if (comp(*first1, *first2)) { + ++first1; + } + else { + ++first1, ++first2; + } + } + return first2 == last2; +} + +/*****************************************************************************************/ +// is_heap +// 检查[first, last)内的元素是否为一个堆,如果是,则返回 true +/*****************************************************************************************/ +template +bool is_heap(RandomIter first, RandomIter last) { + auto n = mystl::distance(first, last); + auto parent = 0; + for (auto child = 1; child < n; ++child) { + if (first[parent] < first[child]) { + return false; + } + if ((child & 1) == 0) { + ++parent; } - return first2 == last2; } + return true; +} - // 重载版本使用函数对象 comp 代替比较操作 - template - bool includes(InputIter1 first1, InputIter1 last1, InputIter2 first2, - InputIter2 last2, Compared comp) { - while (first1 != last1 && first2 != last2) { - if (comp(*first2, *first1)) { - return false; - } - else if (comp(*first1, *first2)) { - ++first1; - } - else { - ++first1, ++first2; - } +// 重载版本使用函数对象 comp 代替比较操作 +template +bool is_heap(RandomIter first, RandomIter last, Compared comp) { + auto n = mystl::distance(first, last); + auto parent = 0; + for (auto child = 1; child < n; ++child) { + if (comp(first[parent], first[child])) { + return false; + } + if ((child & 1) == 0) { + ++parent; } - return first2 == last2; } + return true; +} - /*****************************************************************************************/ - // is_heap - // 检查[first, last)内的元素是否为一个堆,如果是,则返回 true - /*****************************************************************************************/ - template - bool is_heap(RandomIter first, RandomIter last) { - auto n = mystl::distance(first, last); - auto parent = 0; - for (auto child = 1; child < n; ++child) { - if (first[parent] < first[child]) - return false; - if ((child & 1) == 0) - ++parent; - } +/*****************************************************************************************/ +// is_sorted +// 检查[first, last)内的元素是否升序,如果是升序,则返回 true +/*****************************************************************************************/ +template +bool is_sorted(ForwardIter first, ForwardIter last) { + if (first == last) { return true; } - - // 重载版本使用函数对象 comp 代替比较操作 - template - bool is_heap(RandomIter first, RandomIter last, Compared comp) { - auto n = mystl::distance(first, last); - auto parent = 0; - for (auto child = 1; child < n; ++child) { - if (comp(first[parent], first[child])) - return false; - if ((child & 1) == 0) - ++parent; + auto next = first; + ++next; + for (; next != last; first = next, ++next) { + if (*next < *first) { + return false; } - return true; } + return true; +} - /*****************************************************************************************/ - // is_sorted - // 检查[first, last)内的元素是否升序,如果是升序,则返回 true - /*****************************************************************************************/ - template - bool is_sorted(ForwardIter first, ForwardIter last) { - if (first == last) - return true; - auto next = first; - ++next; - for (; next != last; first = next, ++next) { - if (*next < *first) - return false; - } +// 重载版本使用函数对象 comp 代替比较操作 +template +bool is_sorted(ForwardIter first, ForwardIter last, Compared comp) { + if (first == last) { return true; } - - // 重载版本使用函数对象 comp 代替比较操作 - template - bool is_sorted(ForwardIter first, ForwardIter last, Compared comp) { - if (first == last) - return true; - auto next = first; - ++next; - for (; next != last; first = next, ++next) { - if (comp(*next, *first)) - return false; + auto next = first; + ++next; + for (; next != last; first = next, ++next) { + if (comp(*next, *first)) { + return false; } - return true; } + return true; +} - /*****************************************************************************************/ - // median - // 找出三个值的中间值 - /*****************************************************************************************/ - template - const T &median(const T &left, const T &mid, const T &right) { - if (left < mid) - if (mid < right) // left < mid < right - return mid; - else if (left < right) // left < right <= mid - return right; - else // right <= left < mid - return left; - else if (left < right) // mid <= left < right - return left; - else if (mid < right) // mid < right <= left - return right; - else // right <= mid <= left +/*****************************************************************************************/ +// median +// 找出三个值的中间值 +/*****************************************************************************************/ +template +const T& median(const T& left, const T& mid, const T& right) { + if (left < mid) { + if (mid < right) { // left < mid < right return mid; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - const T &median(const T &left, const T &mid, const T &right, - Compared comp) { - if (comp(left, mid)) - if (comp(mid, right)) - return mid; - else if (comp(left, right)) - return right; - else - return left; - else if (comp(left, right)) - return left; - else if (comp(mid, right)) + } + else if (left < right) { // left < right <= mid return right; - else - return mid; - } - - /*****************************************************************************************/ - // max_element - // 返回一个迭代器,指向序列中最大的元素 - /*****************************************************************************************/ - template - ForwardIter max_element(ForwardIter first, ForwardIter last) { - if (first == last) - return first; - auto result = first; - while (++first != last) { - if (*result < *first) - result = first; } - return result; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - ForwardIter max_element(ForwardIter first, ForwardIter last, - Compared comp) { - if (first == last) - return first; - auto result = first; - while (++first != last) { - if (comp(*result, *first)) - result = first; + else { // right <= left < mid + return left; } - return result; } - - /*****************************************************************************************/ - // min_element - // 返回一个迭代器,指向序列中最小的元素 - /*****************************************************************************************/ - template - ForwardIter min_elememt(ForwardIter first, ForwardIter last) { - if (first == last) - return first; - auto result = first; - while (++first != last) { - if (*first < *result) - result = first; - } - return result; + else if (left < right) { // mid <= left < right + return left; } - - // 重载版本使用函数对象 comp 代替比较操作 - template - ForwardIter min_elememt(ForwardIter first, ForwardIter last, - Compared comp) { - if (first == last) - return first; - auto result = first; - while (++first != last) { - if (comp(*first, *result)) - result = first; - } - return result; + else if (mid < right) { // mid < right <= left + return right; } - - /*****************************************************************************************/ - // swap_ranges - // 将[first1, last1)从 first2 开始,交换相同个数元素 - // 交换的区间长度必须相同,两个序列不能互相重叠,返回一个迭代器指向序列二最后一个被交换元素的下一位置 - /*****************************************************************************************/ - template - ForwardIter2 swap_ranges(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2) { - for (; first1 != last1; ++first1, ++first2) { - mystl::iter_swap(first1, first2); - } - return first2; - } - - /*****************************************************************************************/ - // transform - // 第一个版本以函数对象 unary_op 作用于[first, - // last)中的每个元素并将结果保存至 result 中 第二个版本以函数对象 binary_op - // 作用于两个序列[first1, last1)、[first2, last2)的相同位置 - /*****************************************************************************************/ - template - OutputIter transform(InputIter first, InputIter last, OutputIter result, - UnaryOperation unary_op) { - for (; first != last; ++first, ++result) { - *result = unary_op(*first); - } - return result; + else { // right <= mid <= left + return mid; } +} - template - OutputIter transform(InputIter1 first1, InputIter1 last1, InputIter2 first2, - OutputIter result, BinaryOperation binary_op) { - for (; first1 != last1; ++first1, ++first2, ++result) { - *result = binary_op(*first1, *first2); +// 重载版本使用函数对象 comp 代替比较操作 +template +const T& median(const T& left, const T& mid, const T& right, Compared comp) { + if (comp(left, mid)) { + if (comp(mid, right)) { + return mid; } - return result; - } - - /*****************************************************************************************/ - // remove_copy - // 移除区间内与指定 value 相等的元素,并将结果复制到以 result - // 标示起始位置的容器上 - /*****************************************************************************************/ - template - OutputIter remove_copy(InputIter first, InputIter last, OutputIter result, - const T &value) { - for (; first != last; ++first) { - if (*first != value) { - *result++ = *first; - } + else if (comp(left, right)) { + return right; } - return result; - } - - /*****************************************************************************************/ - // remove - // 移除所有与指定 value 相等的元素 - // 并不从容器中删除这些元素,所以 remove 和 remove_if 不适用于 array - /*****************************************************************************************/ - template - ForwardIter remove(ForwardIter first, ForwardIter last, const T &value) { - first = - mystl::find(first, last, value); // 利用 find 找出第一个匹配的地方 - auto next = first; - return first == last ? first - : mystl::remove_copy(++next, last, first, value); - } - - /*****************************************************************************************/ - // remove_copy_if - // 移除区间内所有令一元操作 unary_pred 为 true 的元素,并将结果复制到以 - // result 为起始位置的容器上 - /*****************************************************************************************/ - template - OutputIter remove_copy_if(InputIter first, InputIter last, - OutputIter result, UnaryPredicate unary_pred) { - for (; first != last; ++first) { - if (!unary_pred(*first)) { - *result = *first; - ++result; - } + else { + return left; } - return result; } - - /*****************************************************************************************/ - // remove_if - // 移除区间内所有令一元操作 unary_pred 为 true 的元素 - /*****************************************************************************************/ - template - ForwardIter remove_if(ForwardIter first, ForwardIter last, - UnaryPredicate unary_pred) { - first = mystl::find_if(first, last, - unary_pred); // 利用 find_if 找出第一个匹配的地方 - auto next = first; - return first == last - ? first - : mystl::remove_copy_if(++next, last, first, unary_pred); - } - - /*****************************************************************************************/ - // replace - // 将区间内所有的 old_value 都以 new_value 替代 - /*****************************************************************************************/ - template - void replace(ForwardIter first, ForwardIter last, const T &old_value, - const T &new_value) { - for (; first != last; ++first) { - if (*first == old_value) - *first = new_value; - } - } - - /*****************************************************************************************/ - // replace_copy - // 行为与 replace 类似,不同的是将结果复制到 result - // 所指的容器中,原序列没有改变 - /*****************************************************************************************/ - template - OutputIter replace_copy(InputIter first, InputIter last, OutputIter result, - const T &old_value, const T &new_value) { - for (; first != last; ++first, ++result) { - *result = *first == old_value ? new_value : *first; - } - return result; + else if (comp(left, right)) { + return left; } - - /*****************************************************************************************/ - // replace_copy_if - // 行为与 replace_if 类似,不同的是将结果复制到 result - // 所指的容器中,原序列没有改变 - /*****************************************************************************************/ - template - OutputIter replace_copy_if(InputIter first, InputIter last, - OutputIter result, UnaryPredicate unary_pred, - const T &new_value) { - for (; first != last; ++first, ++result) { - *result = unary_pred(*first) ? new_value : *first; - } - return result; + else if (comp(mid, right)) { + return right; } + else { + return mid; + } +} - /*****************************************************************************************/ - // replace_if - // 将区间内所有令一元操作 unary_pred 为 true 的元素都用 new_value 替代 - /*****************************************************************************************/ - template - void replace_if(ForwardIter first, ForwardIter last, - UnaryPredicate unary_pred, const T &new_value) { - for (; first != last; ++first) { - if (unary_pred(*first)) - *first = new_value; +/*****************************************************************************************/ +// max_element +// 返回一个迭代器,指向序列中最大的元素 +/*****************************************************************************************/ +template +ForwardIter max_element(ForwardIter first, ForwardIter last) { + if (first == last) { + return first; + } + auto result = first; + while (++first != last) { + if (*result < *first) { + result = first; } } + return result; +} - /*****************************************************************************************/ - // reverse - // 将[first, last)区间内的元素反转 - /*****************************************************************************************/ - // reverse_dispatch 的 bidirectional_iterator_tag 版本 - template - void reverse_dispatch(BidirectionalIter first, BidirectionalIter last, - bidirectional_iterator_tag) { - while (true) { - if (first == last || first == --last) - return; - mystl::iter_swap(first++, last); +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter max_element(ForwardIter first, ForwardIter last, Compared comp) { + if (first == last) { + return first; + } + auto result = first; + while (++first != last) { + if (comp(*result, *first)) { + result = first; } } + return result; +} - // reverse_dispatch 的 random_access_iterator_tag 版本 - template - void reverse_dispatch(RandomIter first, RandomIter last, - random_access_iterator_tag) { - while (first < last) - mystl::iter_swap(first++, --last); +/*****************************************************************************************/ +// min_element +// 返回一个迭代器,指向序列中最小的元素 +/*****************************************************************************************/ +template +ForwardIter min_elememt(ForwardIter first, ForwardIter last) { + if (first == last) { + return first; + } + auto result = first; + while (++first != last) { + if (*first < *result) { + result = first; + } } + return result; +} - template - void reverse(BidirectionalIter first, BidirectionalIter last) { - mystl::reverse_dispatch(first, last, iterator_category(first)); +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter min_elememt(ForwardIter first, ForwardIter last, Compared comp) { + if (first == last) { + return first; } - - /*****************************************************************************************/ - // reverse_copy - // 行为与 reverse 类似,不同的是将结果复制到 result 所指容器中 - /*****************************************************************************************/ - template - OutputIter reverse_copy(BidirectionalIter first, BidirectionalIter last, - OutputIter result) { - while (first != last) { - --last; - *result = *last; + auto result = first; + while (++first != last) { + if (comp(*first, *result)) { + result = first; + } + } + return result; +} + +/*****************************************************************************************/ +// swap_ranges +// 将[first1, last1)从 first2 开始,交换相同个数元素 +// 交换的区间长度必须相同,两个序列不能互相重叠,返回一个迭代器指向序列二最后一个被交换元素的下一位置 +/*****************************************************************************************/ +template +ForwardIter2 +swap_ranges(ForwardIter1 first1, ForwardIter1 last1, ForwardIter2 first2) { + for (; first1 != last1; ++first1, ++first2) { + mystl::iter_swap(first1, first2); + } + return first2; +} + +/*****************************************************************************************/ +// transform +// 第一个版本以函数对象 unary_op 作用于[first, +// last)中的每个元素并将结果保存至 result 中 第二个版本以函数对象 binary_op +// 作用于两个序列[first1, last1)、[first2, last2)的相同位置 +/*****************************************************************************************/ +template +OutputIter transform(InputIter first, InputIter last, OutputIter result, + UnaryOperation unary_op) { + for (; first != last; ++first, ++result) { + *result = unary_op(*first); + } + return result; +} + +template +OutputIter transform(InputIter1 first1, InputIter1 last1, InputIter2 first2, + OutputIter result, BinaryOperation binary_op) { + for (; first1 != last1; ++first1, ++first2, ++result) { + *result = binary_op(*first1, *first2); + } + return result; +} + +/*****************************************************************************************/ +// remove_copy +// 移除区间内与指定 value 相等的元素,并将结果复制到以 result +// 标示起始位置的容器上 +/*****************************************************************************************/ +template +OutputIter remove_copy(InputIter first, InputIter last, OutputIter result, + const T& value) { + for (; first != last; ++first) { + if (*first != value) { + *result++ = *first; + } + } + return result; +} + +/*****************************************************************************************/ +// remove +// 移除所有与指定 value 相等的元素 +// 并不从容器中删除这些元素,所以 remove 和 remove_if 不适用于 array +/*****************************************************************************************/ +template +ForwardIter remove(ForwardIter first, ForwardIter last, const T& value) { + first + = mystl::find(first, last, value); // 利用 find 找出第一个匹配的地方 + auto next = first; + return first == last ? first + : mystl::remove_copy(++next, last, first, value); +} + +/*****************************************************************************************/ +// remove_copy_if +// 移除区间内所有令一元操作 unary_pred 为 true 的元素,并将结果复制到以 +// result 为起始位置的容器上 +/*****************************************************************************************/ +template +OutputIter remove_copy_if(InputIter first, InputIter last, OutputIter result, + UnaryPredicate unary_pred) { + for (; first != last; ++first) { + if (!unary_pred(*first)) { + *result = *first; ++result; } - return result; } - - /*****************************************************************************************/ - // random_shuffle - // 将[first, last)内的元素次序随机重排 - // 重载版本使用一个产生随机数的函数对象 rand - /*****************************************************************************************/ - template - void random_shuffle(RandomIter first, RandomIter last) { - if (first == last) + return result; +} + +/*****************************************************************************************/ +// remove_if +// 移除区间内所有令一元操作 unary_pred 为 true 的元素 +/*****************************************************************************************/ +template +ForwardIter +remove_if(ForwardIter first, ForwardIter last, UnaryPredicate unary_pred) { + first = mystl::find_if(first, last, + unary_pred); // 利用 find_if 找出第一个匹配的地方 + auto next = first; + return first == last + ? first + : mystl::remove_copy_if(++next, last, first, unary_pred); +} + +/*****************************************************************************************/ +// replace +// 将区间内所有的 old_value 都以 new_value 替代 +/*****************************************************************************************/ +template +void replace(ForwardIter first, ForwardIter last, const T& old_value, + const T& new_value) { + for (; first != last; ++first) { + if (*first == old_value) { + *first = new_value; + } + } +} + +/*****************************************************************************************/ +// replace_copy +// 行为与 replace 类似,不同的是将结果复制到 result +// 所指的容器中,原序列没有改变 +/*****************************************************************************************/ +template +OutputIter replace_copy(InputIter first, InputIter last, OutputIter result, + const T& old_value, const T& new_value) { + for (; first != last; ++first, ++result) { + *result = *first == old_value ? new_value : *first; + } + return result; +} + +/*****************************************************************************************/ +// replace_copy_if +// 行为与 replace_if 类似,不同的是将结果复制到 result +// 所指的容器中,原序列没有改变 +/*****************************************************************************************/ +template +OutputIter replace_copy_if(InputIter first, InputIter last, OutputIter result, + UnaryPredicate unary_pred, const T& new_value) { + for (; first != last; ++first, ++result) { + *result = unary_pred(*first) ? new_value : *first; + } + return result; +} + +/*****************************************************************************************/ +// replace_if +// 将区间内所有令一元操作 unary_pred 为 true 的元素都用 new_value 替代 +/*****************************************************************************************/ +template +void replace_if(ForwardIter first, ForwardIter last, UnaryPredicate unary_pred, + const T& new_value) { + for (; first != last; ++first) { + if (unary_pred(*first)) { + *first = new_value; + } + } +} + +/*****************************************************************************************/ +// reverse +// 将[first, last)区间内的元素反转 +/*****************************************************************************************/ +// reverse_dispatch 的 bidirectional_iterator_tag 版本 +template +void reverse_dispatch(BidirectionalIter first, BidirectionalIter last, + bidirectional_iterator_tag) { + while (true) { + if (first == last || first == --last) { return; - srand((unsigned)time(0)); - for (auto i = first + 1; i != last; ++i) { - mystl::iter_swap(i, first + (rand() % (i - first + 1))); } - } - - // 重载版本使用一个产生随机数的函数对象 rand - template - void random_shuffle(RandomIter first, RandomIter last, - RandomNumberGenerator &rand) { - if (first == last) - return; - auto len = mystl::distance(first, last); - for (auto i = first + 1; i != last; ++i) { - mystl::iter_swap(i, first + (rand(i - first + 1) % len)); - } - } - - /*****************************************************************************************/ - // rotate - // 将[first, middle)内的元素和 [middle, - // last)内的元素互换,可以交换两个长度不同的区间 返回交换后 middle 的位置 - /*****************************************************************************************/ - // rotate_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter rotate_dispatch(ForwardIter first, ForwardIter middle, - ForwardIter last, forward_iterator_tag) { - auto first2 = middle; - do { - mystl::swap(*first++, *first2++); - if (first == middle) - middle = first2; - } while (first2 != last); // 后半段移到前面 - - auto new_middle = first; // 迭代器返回的位置 - first2 = middle; - while (first2 != last) { // 调整剩余元素 - mystl::swap(*first++, *first2++); - if (first == middle) { - middle = first2; - } - else if (first2 == last) { - first2 = middle; - } + mystl::iter_swap(first++, last); + } +} + +// reverse_dispatch 的 random_access_iterator_tag 版本 +template +void reverse_dispatch(RandomIter first, RandomIter last, + random_access_iterator_tag) { + while (first < last) { + mystl::iter_swap(first++, --last); + } +} + +template +void reverse(BidirectionalIter first, BidirectionalIter last) { + mystl::reverse_dispatch(first, last, iterator_category(first)); +} + +/*****************************************************************************************/ +// reverse_copy +// 行为与 reverse 类似,不同的是将结果复制到 result 所指容器中 +/*****************************************************************************************/ +template +OutputIter reverse_copy(BidirectionalIter first, BidirectionalIter last, + OutputIter result) { + while (first != last) { + --last; + *result = *last; + ++result; + } + return result; +} + +/*****************************************************************************************/ +// random_shuffle +// 将[first, last)内的元素次序随机重排 +// 重载版本使用一个产生随机数的函数对象 rand +/*****************************************************************************************/ +template +void random_shuffle(RandomIter first, RandomIter last) { + if (first == last) { + return; + } + srand((unsigned)time(0)); + for (auto i = first + 1; i != last; ++i) { + mystl::iter_swap(i, first + (rand() % (i - first + 1))); + } +} + +// 重载版本使用一个产生随机数的函数对象 rand +template +void random_shuffle(RandomIter first, RandomIter last, + RandomNumberGenerator& rand) { + if (first == last) { + return; + } + auto len = mystl::distance(first, last); + for (auto i = first + 1; i != last; ++i) { + mystl::iter_swap(i, first + (rand(i - first + 1) % len)); + } +} + +/*****************************************************************************************/ +// rotate +// 将[first, middle)内的元素和 [middle, +// last)内的元素互换,可以交换两个长度不同的区间 返回交换后 middle 的位置 +/*****************************************************************************************/ +// rotate_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter rotate_dispatch(ForwardIter first, ForwardIter middle, + ForwardIter last, forward_iterator_tag) { + auto first2 = middle; + do { + mystl::swap(*first++, *first2++); + if (first == middle) { + middle = first2; } - return new_middle; - } + } while (first2 != last); // 后半段移到前面 - // rotate_dispatch 的 bidirectional_iterator_tag 版本 - template - BidirectionalIter - rotate_dispatch(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, bidirectional_iterator_tag) { - mystl::reverse_dispatch(first, middle, bidirectional_iterator_tag()); - mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag()); - while (first != middle && middle != last) - mystl::swap(*first++, *--last); + auto new_middle = first; // 迭代器返回的位置 + first2 = middle; + while (first2 != last) { // 调整剩余元素 + mystl::swap(*first++, *first2++); if (first == middle) { - mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag()); - return last; + middle = first2; } - else { - mystl::reverse_dispatch(first, middle, - bidirectional_iterator_tag()); - return first; + else if (first2 == last) { + first2 = middle; } } + return new_middle; +} - // 求最大公因子 - template - EuclideanRingElement rgcd(EuclideanRingElement m, EuclideanRingElement n) { - while (n != 0) { - auto t = m % n; - m = n; - n = t; - } - return m; - } - - // rotate_dispatch 的 random_access_iterator_tag 版本 - template - RandomIter rotate_dispatch(RandomIter first, RandomIter middle, - RandomIter last, random_access_iterator_tag) { - // 因为是 random access iterator,我们可以确定每个元素的位置 - auto n = last - first; - auto l = middle - first; - auto r = n - l; - auto result = first + (last - middle); - if (l == r) { - mystl::swap_ranges(first, middle, middle); - return result; - } - auto cycle_times = rgcd(n, l); - for (auto i = 0; i < cycle_times; ++i) { - auto tmp = *first; - auto p = first; - if (l < r) { - for (auto j = 0; j < r / cycle_times; ++j) { - if (p > first + r) { - *p = *(p - r); - p -= r; - } - *p = *(p + l); - p += l; +// rotate_dispatch 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter +rotate_dispatch(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, bidirectional_iterator_tag) { + mystl::reverse_dispatch(first, middle, bidirectional_iterator_tag()); + mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag()); + while (first != middle && middle != last) { + mystl::swap(*first++, *--last); + } + if (first == middle) { + mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag()); + return last; + } + else { + mystl::reverse_dispatch(first, middle, bidirectional_iterator_tag()); + return first; + } +} + +// 求最大公因子 +template +EuclideanRingElement rgcd(EuclideanRingElement m, EuclideanRingElement n) { + while (n != 0) { + auto t = m % n; + m = n; + n = t; + } + return m; +} + +// rotate_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter rotate_dispatch(RandomIter first, RandomIter middle, RandomIter last, + random_access_iterator_tag) { + // 因为是 random access iterator,我们可以确定每个元素的位置 + auto n = last - first; + auto l = middle - first; + auto r = n - l; + auto result = first + (last - middle); + if (l == r) { + mystl::swap_ranges(first, middle, middle); + return result; + } + auto cycle_times = rgcd(n, l); + for (auto i = 0; i < cycle_times; ++i) { + auto tmp = *first; + auto p = first; + if (l < r) { + for (auto j = 0; j < r / cycle_times; ++j) { + if (p > first + r) { + *p = *(p - r); + p -= r; } + *p = *(p + l); + p += l; } - else { - for (auto j = 0; j < l / cycle_times - 1; ++j) { - if (p < last - l) { - *p = *(p + l); - p += l; - } - *p = *(p - r); - p -= r; + } + else { + for (auto j = 0; j < l / cycle_times - 1; ++j) { + if (p < last - l) { + *p = *(p + l); + p += l; } + *p = *(p - r); + p -= r; } - *p = tmp; - ++first; } - return result; + *p = tmp; + ++first; } + return result; +} - template - ForwardIter rotate(ForwardIter first, ForwardIter middle, - ForwardIter last) { - if (first == middle) - return last; - if (middle == last) - return first; - return mystl::rotate_dispatch(first, middle, last, - iterator_category(first)); - } - - /*****************************************************************************************/ - // rotate_copy - // 行为与 rotate 类似,不同的是将结果复制到 result 所指的容器中 - /*****************************************************************************************/ - template - ForwardIter rotate_copy(ForwardIter first, ForwardIter middle, - ForwardIter last, OutputIter result) { - return mystl::copy(first, middle, mystl::copy(middle, last, result)); - } - - /*****************************************************************************************/ - // is_permutation - // 判断[first1,last1)是否为[first2, last2)的排列组合 - /*****************************************************************************************/ - template - bool is_permutation_aux(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2, - BinaryPred pred) { - constexpr bool is_ra_it = - mystl::is_random_access_iterator::value && - mystl::is_random_access_iterator::value; - if (is_ra_it) { - auto len1 = last1 - first1; - auto len2 = last2 - first2; - if (len1 != len2) - return false; +template +ForwardIter rotate(ForwardIter first, ForwardIter middle, ForwardIter last) { + if (first == middle) { + return last; + } + if (middle == last) { + return first; + } + return mystl::rotate_dispatch(first, middle, last, + iterator_category(first)); +} + +/*****************************************************************************************/ +// rotate_copy +// 行为与 rotate 类似,不同的是将结果复制到 result 所指的容器中 +/*****************************************************************************************/ +template +ForwardIter rotate_copy(ForwardIter first, ForwardIter middle, ForwardIter last, + OutputIter result) { + return mystl::copy(first, middle, mystl::copy(middle, last, result)); +} + +/*****************************************************************************************/ +// is_permutation +// 判断[first1,last1)是否为[first2, last2)的排列组合 +/*****************************************************************************************/ +template +bool is_permutation_aux(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, + BinaryPred pred) { + constexpr bool is_ra_it + = mystl::is_random_access_iterator::value + && mystl::is_random_access_iterator::value; + if (is_ra_it) { + auto len1 = last1 - first1; + auto len2 = last2 - first2; + if (len1 != len2) { + return false; } + } - // 先找出相同的前缀段 - for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) { - if (!pred(*first1, *first2)) - break; + // 先找出相同的前缀段 + for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) { + if (!pred(*first1, *first2)) { + break; } - if (is_ra_it) { - if (first1 == last1) - return true; + } + if (is_ra_it) { + if (first1 == last1) { + return true; } - else { - auto len1 = mystl::distance(first1, last1); - auto len2 = mystl::distance(first2, last2); - if (len1 == 0 && len2 == 0) - return true; - if (len1 != len2) - return false; + } + else { + auto len1 = mystl::distance(first1, last1); + auto len2 = mystl::distance(first2, last2); + if (len1 == 0 && len2 == 0) { + return true; + } + if (len1 != len2) { + return false; } + } - // 判断剩余部分 - for (auto i = first1; i != last1; ++i) { - bool is_repeated = false; - for (auto j = first1; j != i; ++j) { - if (pred(*j, *i)) { - is_repeated = true; - break; - } + // 判断剩余部分 + for (auto i = first1; i != last1; ++i) { + bool is_repeated = false; + for (auto j = first1; j != i; ++j) { + if (pred(*j, *i)) { + is_repeated = true; + break; } + } - if (!is_repeated) { - // 计算 *i 在 [first2, last2) 的数目 - auto c2 = 0; - for (auto j = first2; j != last2; ++j) { - if (pred(*i, *j)) - ++c2; - } - if (c2 == 0) - return false; - - // 计算 *i 在 [first1, last1) 的数目 - auto c1 = 1; - auto j = i; - for (++j; j != last1; ++j) { - if (pred(*i, *j)) - ++c1; + if (!is_repeated) { + // 计算 *i 在 [first2, last2) 的数目 + auto c2 = 0; + for (auto j = first2; j != last2; ++j) { + if (pred(*i, *j)) { + ++c2; } - if (c1 != c2) - return false; } - } - return true; - } + if (c2 == 0) { + return false; + } - template - bool is_permutation(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2, - BinaryPred pred) { - return is_permutation_aux(first1, last1, first2, last2, pred); - } - - template - bool is_permutation(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2, ForwardIter2 last2) { - typedef typename iterator_traits::value_type v1; - typedef typename iterator_traits::value_type v2; - static_assert(std::is_same::value, - "the type should be same in mystl::is_permutation"); - return is_permutation_aux(first1, last1, first2, last2, - mystl::equal_to()); - } - - /*****************************************************************************************/ - // next_permutation - // 取得[first, last)所标示序列的下一个排列组合,如果没有下一个排序组合,返回 - // false,否则返回 true - /*****************************************************************************************/ - template - bool next_permutation(BidirectionalIter first, BidirectionalIter last) { - auto i = last; - if (first == last || first == --i) - return false; - for (;;) { - auto ii = i; - if (*--i < *ii) { // 找到第一对小于关系的元素 - auto j = last; - while (!(*i < *--j)) {} - mystl::iter_swap(i, j); // 交换 i,j 所指元素 - mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 - return true; + // 计算 *i 在 [first1, last1) 的数目 + auto c1 = 1; + auto j = i; + for (++j; j != last1; ++j) { + if (pred(*i, *j)) { + ++c1; + } } - if (i == first) { - mystl::reverse(first, last); + if (c1 != c2) { return false; } } } - - // 重载版本使用函数对象 comp 代替比较操作 - template - bool next_permutation(BidirectionalIter first, BidirectionalIter last, - Compared comp) { - auto i = last; - if (first == last || first == --i) - return false; - for (;;) { - auto ii = i; - if (comp(*--i, *ii)) { - auto j = last; - while (!comp(*i, *--j)) {} - mystl::iter_swap(i, j); // 交换 i,j 所指元素 - mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 - return true; - } - if (i == first) { - mystl::reverse(first, last); - return false; + return true; +} + +template +bool is_permutation(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, BinaryPred pred) { + return is_permutation_aux(first1, last1, first2, last2, pred); +} + +template +bool is_permutation(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2) { + typedef typename iterator_traits::value_type v1; + typedef typename iterator_traits::value_type v2; + static_assert(std::is_same::value, + "the type should be same in mystl::is_permutation"); + return is_permutation_aux(first1, last1, first2, last2, + mystl::equal_to()); +} + +/*****************************************************************************************/ +// next_permutation +// 取得[first, last)所标示序列的下一个排列组合,如果没有下一个排序组合,返回 +// false,否则返回 true +/*****************************************************************************************/ +template +bool next_permutation(BidirectionalIter first, BidirectionalIter last) { + auto i = last; + if (first == last || first == --i) { + return false; + } + for (;;) { + auto ii = i; + if (*--i < *ii) { // 找到第一对小于关系的元素 + auto j = last; + while (!(*i < *--j)) { } + mystl::iter_swap(i, j); // 交换 i,j 所指元素 + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) { + mystl::reverse(first, last); + return false; } } +} - /*****************************************************************************************/ - // prev_permutation - // 取得[first, last)所标示序列的上一个排列组合,如果没有上一个排序组合,返回 - // false,否则返回 true - /*****************************************************************************************/ - template - bool prev_permutation(BidirectionalIter first, BidirectionalIter last) { - auto i = last; - if (first == last || first == --i) - return false; - for (;;) { - auto ii = i; - if (*ii < *--i) { // 找到第一对大于关系的元素 - auto j = last; - while (!(*--j < *i)) {} - mystl::iter_swap(i, j); // 交换i,j - mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 - return true; - } - if (i == first) { - mystl::reverse(first, last); - return false; +// 重载版本使用函数对象 comp 代替比较操作 +template +bool next_permutation(BidirectionalIter first, BidirectionalIter last, + Compared comp) { + auto i = last; + if (first == last || first == --i) { + return false; + } + for (;;) { + auto ii = i; + if (comp(*--i, *ii)) { + auto j = last; + while (!comp(*i, *--j)) { } + mystl::iter_swap(i, j); // 交换 i,j 所指元素 + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) { + mystl::reverse(first, last); + return false; } } +} - // 重载版本使用函数对象 comp 代替比较操作 - template - bool prev_permutation(BidirectionalIter first, BidirectionalIter last, - Compared comp) { - auto i = last; - if (first == last || first == --i) - return false; - for (;;) { - auto ii = i; - if (comp(*ii, *--i)) { - auto j = last; - while (!comp(*--j, *i)) {} - mystl::iter_swap(i, j); // 交换i,j - mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 - return true; - } - if (i == first) { - mystl::reverse(first, last); - return false; +/*****************************************************************************************/ +// prev_permutation +// 取得[first, last)所标示序列的上一个排列组合,如果没有上一个排序组合,返回 +// false,否则返回 true +/*****************************************************************************************/ +template +bool prev_permutation(BidirectionalIter first, BidirectionalIter last) { + auto i = last; + if (first == last || first == --i) { + return false; + } + for (;;) { + auto ii = i; + if (*ii < *--i) { // 找到第一对大于关系的元素 + auto j = last; + while (!(*--j < *i)) { } + mystl::iter_swap(i, j); // 交换i,j + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) { + mystl::reverse(first, last); + return false; } } +} - /*****************************************************************************************/ - // merge - // 将两个经过排序的集合 S1 和 S2 - // 合并起来置于另一段空间,返回一个迭代器指向最后一个元素的下一位置 - /*****************************************************************************************/ - template - OutputIter merge(InputIter1 first1, InputIter1 last1, InputIter2 first2, - InputIter2 last2, OutputIter result) { - while (first1 != last1 && first2 != last2) { - if (*first2 < *first1) { - *result = *first2; - ++first2; - } - else { - *result = *first1; - ++first1; +// 重载版本使用函数对象 comp 代替比较操作 +template +bool prev_permutation(BidirectionalIter first, BidirectionalIter last, + Compared comp) { + auto i = last; + if (first == last || first == --i) { + return false; + } + for (;;) { + auto ii = i; + if (comp(*ii, *--i)) { + auto j = last; + while (!comp(*--j, *i)) { } - ++result; + mystl::iter_swap(i, j); // 交换i,j + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) { + mystl::reverse(first, last); + return false; } - return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); } +} - // 重载版本使用函数对象 comp 代替比较操作 - template - OutputIter merge(InputIter1 first1, InputIter1 last1, InputIter2 first2, - InputIter2 last2, OutputIter result, Compared comp) { - while (first1 != last1 && first2 != last2) { - if (comp(*first2, *first1)) { - *result = *first2; - ++first2; - } - else { - *result = *first1; - ++first1; - } - ++result; +/*****************************************************************************************/ +// merge +// 将两个经过排序的集合 S1 和 S2 +// 合并起来置于另一段空间,返回一个迭代器指向最后一个元素的下一位置 +/*****************************************************************************************/ +template +OutputIter merge(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result) { + while (first1 != last1 && first2 != last2) { + if (*first2 < *first1) { + *result = *first2; + ++first2; + } + else { + *result = *first1; + ++first1; } - return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); + ++result; } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} - /*****************************************************************************************/ - // inplace_merge - // 把连接在一起的两个有序序列结合成单一序列并保持有序 - /*****************************************************************************************/ - // 没有缓冲区的情况下合并 - template - void merge_without_buffer(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, Distance len1, - Distance len2) { - if (len1 == 0 || len2 == 0) - return; - if (len1 + len2 == 2) { - if (*middle < *first) - mystl::iter_swap(first, middle); - return; +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter merge(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result, Compared comp) { + while (first1 != last1 && first2 != last2) { + if (comp(*first2, *first1)) { + *result = *first2; + ++first2; + } + else { + *result = *first1; + ++first1; + } + ++result; + } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} + +/*****************************************************************************************/ +// inplace_merge +// 把连接在一起的两个有序序列结合成单一序列并保持有序 +/*****************************************************************************************/ +// 没有缓冲区的情况下合并 +template +void merge_without_buffer(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, + Distance len2) { + if (len1 == 0 || len2 == 0) { + return; + } + if (len1 + len2 == 2) { + if (*middle < *first) { + mystl::iter_swap(first, middle); + } + return; + } + auto first_cut = first; + auto second_cut = middle; + Distance len11 = 0; + Distance len22 = 0; + if (len1 > len2) { // 序列一较长,找到序列一的中点 + len11 = len1 >> 1; + mystl::advance(first_cut, len11); + second_cut = mystl::lower_bound(middle, last, *first_cut); + len22 = mystl::distance(middle, second_cut); + } + else { // 序列二较长,找到序列二的中点 + len22 = len2 >> 1; + mystl::advance(second_cut, len22); + first_cut = mystl::upper_bound(first, middle, *second_cut); + len11 = mystl::distance(first, first_cut); + } + auto new_middle = mystl::rotate(first_cut, middle, second_cut); + mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22); + mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, + len2 - len22); +} + +template +BidirectionalIter1 +merge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + BidirectionalIter1 result) { + if (first1 == last1) { + return mystl::copy_backward(first2, last2, result); + } + if (first2 == last2) { + return mystl::copy_backward(first1, last1, result); + } + --last1; + --last2; + while (true) { + if (*last2 < *last1) { + *--result = *last1; + if (first1 == last1) { + return mystl::copy_backward(first2, ++last2, result); + } + --last1; } + else { + *--result = *last2; + if (first2 == last2) { + return mystl::copy_backward(first1, ++last1, result); + } + --last2; + } + } +} + +template +BidirectionalIter1 +rotate_adaptive(BidirectionalIter1 first, BidirectionalIter1 middle, + BidirectionalIter1 last, Distance len1, Distance len2, + BidirectionalIter2 buffer, Distance buffer_size) { + BidirectionalIter2 buffer_end; + if (len1 > len2 && len2 <= buffer_size) { + buffer_end = mystl::copy(middle, last, buffer); + mystl::copy_backward(first, middle, last); + return mystl::copy(buffer, buffer_end, first); + } + else if (len1 <= buffer_size) { + buffer_end = mystl::copy(first, middle, buffer); + mystl::copy(middle, last, first); + return mystl::copy_backward(buffer, buffer_end, last); + } + else { + return mystl::rotate(first, middle, last); + } +} + +// 有缓冲区的情况下合并 +template +void merge_adaptive(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, Distance len2, + Pointer buffer, Distance buffer_size) { + // 区间长度足够放进缓冲区 + if (len1 <= len2 && len1 <= buffer_size) { + Pointer buffer_end = mystl::copy(first, middle, buffer); + mystl::merge(buffer, buffer_end, middle, last, first); + } + else if (len2 <= buffer_size) { + Pointer buffer_end = mystl::copy(middle, last, buffer); + mystl::merge_backward(first, middle, buffer, buffer_end, last); + } + else { // 区间长度太长,分割递归处理 auto first_cut = first; auto second_cut = middle; Distance len11 = 0; Distance len22 = 0; - if (len1 > len2) { // 序列一较长,找到序列一的中点 + if (len1 > len2) { len11 = len1 >> 1; mystl::advance(first_cut, len11); second_cut = mystl::lower_bound(middle, last, *first_cut); len22 = mystl::distance(middle, second_cut); } - else { // 序列二较长,找到序列二的中点 + else { len22 = len2 >> 1; mystl::advance(second_cut, len22); first_cut = mystl::upper_bound(first, middle, *second_cut); len11 = mystl::distance(first, first_cut); } - auto new_middle = mystl::rotate(first_cut, middle, second_cut); - mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22); - mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, - len2 - len22); - } - - template - BidirectionalIter1 - merge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1, - BidirectionalIter2 first2, BidirectionalIter2 last2, - BidirectionalIter1 result) { - if (first1 == last1) - return mystl::copy_backward(first2, last2, result); - if (first2 == last2) - return mystl::copy_backward(first1, last1, result); - --last1; - --last2; - while (true) { - if (*last2 < *last1) { - *--result = *last1; - if (first1 == last1) - return mystl::copy_backward(first2, ++last2, result); - --last1; - } - else { - *--result = *last2; - if (first2 == last2) - return mystl::copy_backward(first1, ++last1, result); - --last2; - } - } - } - - template - BidirectionalIter1 - rotate_adaptive(BidirectionalIter1 first, BidirectionalIter1 middle, - BidirectionalIter1 last, Distance len1, Distance len2, - BidirectionalIter2 buffer, Distance buffer_size) { - BidirectionalIter2 buffer_end; - if (len1 > len2 && len2 <= buffer_size) { - buffer_end = mystl::copy(middle, last, buffer); - mystl::copy_backward(first, middle, last); - return mystl::copy(buffer, buffer_end, first); - } - else if (len1 <= buffer_size) { - buffer_end = mystl::copy(first, middle, buffer); - mystl::copy(middle, last, first); - return mystl::copy_backward(buffer, buffer_end, last); + auto new_middle + = mystl::rotate_adaptive(first_cut, middle, second_cut, len1 - len11, + len22, buffer, buffer_size); + mystl::merge_adaptive(first, first_cut, new_middle, len11, len22, + buffer, buffer_size); + mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11, + len2 - len22, buffer, buffer_size); + } +} + +template +void inplace_merge_aux(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, T*) { + auto len1 = mystl::distance(first, middle); + auto len2 = mystl::distance(middle, last); + temporary_buffer buf(first, last); + if (!buf.begin()) { + mystl::merge_without_buffer(first, middle, last, len1, len2); + } + else { + mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), + buf.size()); + } +} + +template +void inplace_merge(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last) { + if (first == middle || middle == last) { + return; + } + mystl::inplace_merge_aux(first, middle, last, value_type(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// 没有缓冲区的情况下合并 +template +void merge_without_buffer(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, Distance len2, + Compared comp) { + if (len1 == 0 || len2 == 0) { + return; + } + if (len1 + len2 == 2) { + if (comp(*middle, *first)) { + mystl::iter_swap(first, middle); + } + return; + } + auto first_cut = first; + auto second_cut = middle; + Distance len11 = 0; + Distance len22 = 0; + if (len1 > len2) { + len11 = len1 >> 1; + mystl::advance(first_cut, len11); + second_cut = mystl::lower_bound(middle, last, *first_cut, comp); + len22 = mystl::distance(middle, second_cut); + } + else { + len22 = len2 >> 1; + mystl::advance(second_cut, len22); + first_cut = mystl::upper_bound(first, middle, *second_cut, comp); + len11 = mystl::distance(first, first_cut); + } + auto new_middle = mystl::rotate(first_cut, middle, second_cut); + mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22, + comp); + mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, + len2 - len22, comp); +} + +template +BidirectionalIter1 +merge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + BidirectionalIter1 result, Compared comp) { + if (first1 == last1) { + return mystl::copy_backward(first2, last2, result); + } + if (first2 == last2) { + return mystl::copy_backward(first1, last1, result); + } + --last1; + --last2; + while (true) { + if (comp(*last2, *last1)) { + *--result = *last1; + if (first1 == last1) { + return mystl::copy_backward(first2, ++last2, result); + } + --last1; } else { - return mystl::rotate(first, middle, last); - } - } - - // 有缓冲区的情况下合并 - template - void merge_adaptive(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, Distance len1, Distance len2, - Pointer buffer, Distance buffer_size) { - // 区间长度足够放进缓冲区 - if (len1 <= len2 && len1 <= buffer_size) { - Pointer buffer_end = mystl::copy(first, middle, buffer); - mystl::merge(buffer, buffer_end, middle, last, first); - } - else if (len2 <= buffer_size) { - Pointer buffer_end = mystl::copy(middle, last, buffer); - mystl::merge_backward(first, middle, buffer, buffer_end, last); - } - else { // 区间长度太长,分割递归处理 - auto first_cut = first; - auto second_cut = middle; - Distance len11 = 0; - Distance len22 = 0; - if (len1 > len2) { - len11 = len1 >> 1; - mystl::advance(first_cut, len11); - second_cut = mystl::lower_bound(middle, last, *first_cut); - len22 = mystl::distance(middle, second_cut); + *--result = *last2; + if (first2 == last2) { + return mystl::copy_backward(first1, ++last1, result); } - else { - len22 = len2 >> 1; - mystl::advance(second_cut, len22); - first_cut = mystl::upper_bound(first, middle, *second_cut); - len11 = mystl::distance(first, first_cut); - } - auto new_middle = mystl::rotate_adaptive( - first_cut, middle, second_cut, len1 - len11, len22, buffer, - buffer_size); - mystl::merge_adaptive(first, first_cut, new_middle, len11, len22, - buffer, buffer_size); - mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11, - len2 - len22, buffer, buffer_size); + --last2; } } +} - template - void inplace_merge_aux(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, T *) { - auto len1 = mystl::distance(first, middle); - auto len2 = mystl::distance(middle, last); - temporary_buffer buf(first, last); - if (!buf.begin()) { - mystl::merge_without_buffer(first, middle, last, len1, len2); - } - else { - mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), - buf.size()); - } +// 有缓冲区的情况下合并 +template +void merge_adaptive(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, Distance len2, + Pointer buffer, Distance buffer_size, Compared comp) { + // 区间长度足够放进缓冲区 + if (len1 <= len2 && len1 <= buffer_size) { + Pointer buffer_end = mystl::copy(first, middle, buffer); + mystl::merge(buffer, buffer_end, middle, last, first, comp); } - - template - void inplace_merge(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last) { - if (first == middle || middle == last) - return; - mystl::inplace_merge_aux(first, middle, last, value_type(first)); + else if (len2 <= buffer_size) { + Pointer buffer_end = mystl::copy(middle, last, buffer); + mystl::merge_backward(first, middle, buffer, buffer_end, last, comp); } - - // 重载版本使用函数对象 comp 代替比较操作 - // 没有缓冲区的情况下合并 - template - void merge_without_buffer(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, Distance len1, - Distance len2, Compared comp) { - if (len1 == 0 || len2 == 0) - return; - if (len1 + len2 == 2) { - if (comp(*middle, *first)) - mystl::iter_swap(first, middle); - return; - } + else { // 区间长度太长,分割递归处理 auto first_cut = first; auto second_cut = middle; Distance len11 = 0; @@ -1820,605 +1955,555 @@ namespace mystl { first_cut = mystl::upper_bound(first, middle, *second_cut, comp); len11 = mystl::distance(first, first_cut); } - auto new_middle = mystl::rotate(first_cut, middle, second_cut); - mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22, - comp); - mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, - len2 - len22, comp); - } - - template - BidirectionalIter1 - merge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1, - BidirectionalIter2 first2, BidirectionalIter2 last2, - BidirectionalIter1 result, Compared comp) { - if (first1 == last1) - return mystl::copy_backward(first2, last2, result); - if (first2 == last2) - return mystl::copy_backward(first1, last1, result); - --last1; - --last2; - while (true) { - if (comp(*last2, *last1)) { - *--result = *last1; - if (first1 == last1) - return mystl::copy_backward(first2, ++last2, result); - --last1; - } - else { - *--result = *last2; - if (first2 == last2) - return mystl::copy_backward(first1, ++last1, result); - --last2; - } - } - } - - // 有缓冲区的情况下合并 - template - void merge_adaptive(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, Distance len1, Distance len2, - Pointer buffer, Distance buffer_size, Compared comp) { - // 区间长度足够放进缓冲区 - if (len1 <= len2 && len1 <= buffer_size) { - Pointer buffer_end = mystl::copy(first, middle, buffer); - mystl::merge(buffer, buffer_end, middle, last, first, comp); + auto new_middle + = mystl::rotate_adaptive(first_cut, middle, second_cut, len1 - len11, + len22, buffer, buffer_size); + mystl::merge_adaptive(first, first_cut, new_middle, len11, len22, + buffer, buffer_size, comp); + mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11, + len2 - len22, buffer, buffer_size, comp); + } +} + +template +void inplace_merge_aux(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, T*, Compared comp) { + auto len1 = mystl::distance(first, middle); + auto len2 = mystl::distance(middle, last); + temporary_buffer buf(first, last); + if (!buf.begin()) { + mystl::merge_without_buffer(first, middle, last, len1, len2, comp); + } + else { + mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), + buf.size(), comp); + } +} + +template +void inplace_merge(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Compared comp) { + if (first == middle || middle == last) { + return; + } + mystl::inplace_merge_aux(first, middle, last, value_type(first), comp); +} + +/*****************************************************************************************/ +// partial_sort +// 对整个序列做部分排序,保证较小的 N 个元素以递增顺序置于[first, first + +// N)中 +/*****************************************************************************************/ +template +void partial_sort(RandomIter first, RandomIter middle, RandomIter last) { + mystl::make_heap(first, middle); + for (auto i = middle; i < last; ++i) { + if (*i < *first) { + mystl::pop_heap_aux(first, middle, i, *i, distance_type(first)); + } + } + mystl::sort_heap(first, middle); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void partial_sort(RandomIter first, RandomIter middle, RandomIter last, + Compared comp) { + mystl::make_heap(first, middle, comp); + for (auto i = middle; i < last; ++i) { + if (comp(*i, *first)) { + mystl::pop_heap_aux(first, middle, i, *i, distance_type(first), + comp); + } + } + mystl::sort_heap(first, middle, comp); +} + +/*****************************************************************************************/ +// partial_sort_copy +// 行为与 partial_sort 类似,不同的是把排序结果复制到 result 容器中 +/*****************************************************************************************/ +template +RandomIter +psort_copy_aux(InputIter first, InputIter last, RandomIter result_first, + RandomIter result_last, Distance*) { + if (result_first == result_last) { + return result_last; + } + auto result_iter = result_first; + while (first != last && result_iter != result_last) { + *result_iter = *first; + ++result_iter; + ++first; + } + mystl::make_heap(result_first, result_iter); + while (first != last) { + if (*first < *result_first) { + mystl::adjust_heap(result_first, static_cast(0), + result_iter - result_first, *first); + } + ++first; + } + mystl::sort_heap(result_first, result_iter); + return result_iter; +} + +template +RandomIter partial_sort_copy(InputIter first, InputIter last, + RandomIter result_first, RandomIter result_last) { + return mystl::psort_copy_aux(first, last, result_first, result_last, + distance_type(result_first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +RandomIter +psort_copy_aux(InputIter first, InputIter last, RandomIter result_first, + RandomIter result_last, Distance*, Compared comp) { + if (result_first == result_last) { + return result_last; + } + auto result_iter = result_first; + while (first != last && result_iter != result_last) { + *result_iter = *first; + ++result_iter; + ++first; + } + mystl::make_heap(result_first, result_iter, comp); + while (first != last) { + if (comp(*first, *result_first)) { + mystl::adjust_heap(result_first, static_cast(0), + result_iter - result_first, *first, comp); + } + ++first; + } + mystl::sort_heap(result_first, result_iter, comp); + return result_iter; +} + +template +RandomIter +partial_sort_copy(InputIter first, InputIter last, RandomIter result_first, + RandomIter result_last, Compared comp) { + return mystl::psort_copy_aux(first, last, result_first, result_last, + distance_type(result_first), comp); +} + +/*****************************************************************************************/ +// partition +// 对区间内的元素重排,被一元条件运算判定为 true 的元素会放到区间的前段 +// 该函数不保证元素的原始相对位置 +/*****************************************************************************************/ +template +BidirectionalIter partition(BidirectionalIter first, BidirectionalIter last, + UnaryPredicate unary_pred) { + while (true) { + while (first != last && unary_pred(*first)) { + ++first; } - else if (len2 <= buffer_size) { - Pointer buffer_end = mystl::copy(middle, last, buffer); - mystl::merge_backward(first, middle, buffer, buffer_end, last, - comp); + if (first == last) { + break; } - else { // 区间长度太长,分割递归处理 - auto first_cut = first; - auto second_cut = middle; - Distance len11 = 0; - Distance len22 = 0; - if (len1 > len2) { - len11 = len1 >> 1; - mystl::advance(first_cut, len11); - second_cut = mystl::lower_bound(middle, last, *first_cut, comp); - len22 = mystl::distance(middle, second_cut); - } - else { - len22 = len2 >> 1; - mystl::advance(second_cut, len22); - first_cut = - mystl::upper_bound(first, middle, *second_cut, comp); - len11 = mystl::distance(first, first_cut); - } - auto new_middle = mystl::rotate_adaptive( - first_cut, middle, second_cut, len1 - len11, len22, buffer, - buffer_size); - mystl::merge_adaptive(first, first_cut, new_middle, len11, len22, - buffer, buffer_size, comp); - mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11, - len2 - len22, buffer, buffer_size, comp); + --last; + while (first != last && !unary_pred(*last)) { + --last; } - } - - template - void inplace_merge_aux(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, T *, Compared comp) { - auto len1 = mystl::distance(first, middle); - auto len2 = mystl::distance(middle, last); - temporary_buffer buf(first, last); - if (!buf.begin()) { - mystl::merge_without_buffer(first, middle, last, len1, len2, comp); + if (first == last) { + break; + } + mystl::iter_swap(first, last); + ++first; + } + return first; +} + +/*****************************************************************************************/ +// partition_copy +// 行为与 partition 类似,不同的是,将被一元操作符判定为 true 的放到 +// result_true 的输出区间 其余放到 result_false 的输出区间,并返回一个 +// mystl::pair 指向这两个区间的尾部 +/*****************************************************************************************/ +template +mystl::pair +partition_copy(InputIter first, InputIter last, OutputIter1 result_true, + OutputIter2 result_false, UnaryPredicate unary_pred) { + for (; first != last; ++first) { + if (unary_pred(*first)) { + *result_true++ = *first; } else { - mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), - buf.size(), comp); - } - } - - template - void inplace_merge(BidirectionalIter first, BidirectionalIter middle, - BidirectionalIter last, Compared comp) { - if (first == middle || middle == last) - return; - mystl::inplace_merge_aux(first, middle, last, value_type(first), comp); - } - - /*****************************************************************************************/ - // partial_sort - // 对整个序列做部分排序,保证较小的 N 个元素以递增顺序置于[first, first + - // N)中 - /*****************************************************************************************/ - template - void partial_sort(RandomIter first, RandomIter middle, RandomIter last) { - mystl::make_heap(first, middle); - for (auto i = middle; i < last; ++i) { - if (*i < *first) { - mystl::pop_heap_aux(first, middle, i, *i, distance_type(first)); - } - } - mystl::sort_heap(first, middle); - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - void partial_sort(RandomIter first, RandomIter middle, RandomIter last, - Compared comp) { - mystl::make_heap(first, middle, comp); - for (auto i = middle; i < last; ++i) { - if (comp(*i, *first)) { - mystl::pop_heap_aux(first, middle, i, *i, distance_type(first), - comp); - } - } - mystl::sort_heap(first, middle, comp); - } - - /*****************************************************************************************/ - // partial_sort_copy - // 行为与 partial_sort 类似,不同的是把排序结果复制到 result 容器中 - /*****************************************************************************************/ - template - RandomIter psort_copy_aux(InputIter first, InputIter last, - RandomIter result_first, RandomIter result_last, - Distance *) { - if (result_first == result_last) - return result_last; - auto result_iter = result_first; - while (first != last && result_iter != result_last) { - *result_iter = *first; - ++result_iter; - ++first; - } - mystl::make_heap(result_first, result_iter); - while (first != last) { - if (*first < *result_first) { - mystl::adjust_heap(result_first, static_cast(0), - result_iter - result_first, *first); - } - ++first; - } - mystl::sort_heap(result_first, result_iter); - return result_iter; - } - - template - RandomIter partial_sort_copy(InputIter first, InputIter last, - RandomIter result_first, - RandomIter result_last) { - return mystl::psort_copy_aux(first, last, result_first, result_last, - distance_type(result_first)); - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - RandomIter psort_copy_aux(InputIter first, InputIter last, - RandomIter result_first, RandomIter result_last, - Distance *, Compared comp) { - if (result_first == result_last) - return result_last; - auto result_iter = result_first; - while (first != last && result_iter != result_last) { - *result_iter = *first; - ++result_iter; - ++first; - } - mystl::make_heap(result_first, result_iter, comp); - while (first != last) { - if (comp(*first, *result_first)) { - mystl::adjust_heap(result_first, static_cast(0), - result_iter - result_first, *first, comp); - } + *result_false++ = *first; + } + } + return mystl::pair(result_true, result_false); +} + +/*****************************************************************************************/ +// sort +// 将[first, last)内的元素以递增的方式排序 +/*****************************************************************************************/ +constexpr static size_t kSmallSectionSize + = 128; // 小型区间的大小,在这个大小内采用插入排序 + +// 用于控制分割恶化的情况 +template +Size slg2(Size n) { // 找出 lgk <= n 的 k 的最大值 + Size k = 0; + for (; n > 1; n >>= 1) { + ++k; + } + return k; +} + +// 分割函数 unchecked_partition +template +RandomIter +unchecked_partition(RandomIter first, RandomIter last, const T& pivot) { + while (true) { + while (*first < pivot) { ++first; } - mystl::sort_heap(result_first, result_iter, comp); - return result_iter; - } - - template - RandomIter partial_sort_copy(InputIter first, InputIter last, - RandomIter result_first, - RandomIter result_last, Compared comp) { - return mystl::psort_copy_aux(first, last, result_first, result_last, - distance_type(result_first), comp); - } - /*****************************************************************************************/ - // partition - // 对区间内的元素重排,被一元条件运算判定为 true 的元素会放到区间的前段 - // 该函数不保证元素的原始相对位置 - /*****************************************************************************************/ - template - BidirectionalIter partition(BidirectionalIter first, BidirectionalIter last, - UnaryPredicate unary_pred) { - while (true) { - while (first != last && unary_pred(*first)) { - ++first; - } - if (first == last) - break; + --last; + while (pivot < *last) { --last; - while (first != last && !unary_pred(*last)) { - --last; - } - if (first == last) - break; - mystl::iter_swap(first, last); - ++first; - } - return first; - } - - /*****************************************************************************************/ - // partition_copy - // 行为与 partition 类似,不同的是,将被一元操作符判定为 true 的放到 - // result_true 的输出区间 其余放到 result_false 的输出区间,并返回一个 - // mystl::pair 指向这两个区间的尾部 - /*****************************************************************************************/ - template - mystl::pair - partition_copy(InputIter first, InputIter last, OutputIter1 result_true, - OutputIter2 result_false, UnaryPredicate unary_pred) { - for (; first != last; ++first) { - if (unary_pred(*first)) { - *result_true++ = *first; - } - else { - *result_false++ = *first; - } } - return mystl::pair(result_true, result_false); - } - - /*****************************************************************************************/ - // sort - // 将[first, last)内的元素以递增的方式排序 - /*****************************************************************************************/ - constexpr static size_t kSmallSectionSize = - 128; // 小型区间的大小,在这个大小内采用插入排序 - - // 用于控制分割恶化的情况 - template - Size slg2(Size n) { // 找出 lgk <= n 的 k 的最大值 - Size k = 0; - for (; n > 1; n >>= 1) - ++k; - return k; - } - - // 分割函数 unchecked_partition - template - RandomIter unchecked_partition(RandomIter first, RandomIter last, - const T &pivot) { - while (true) { - while (*first < pivot) - ++first; - --last; - while (pivot < *last) - --last; - if (!(first < last)) - return first; - mystl::iter_swap(first, last); - ++first; + if (!(first < last)) { + return first; } + mystl::iter_swap(first, last); + ++first; } +} - // 内省式排序,先进行 quick sort,当分割行为有恶化倾向时,改用 heap sort - template - void intro_sort(RandomIter first, RandomIter last, Size depth_limit) { - while (static_cast(last - first) > kSmallSectionSize) { - if (depth_limit == 0) { // 到达最大分割深度限制 - mystl::partial_sort(first, last, last); // 改用 heap_sort - return; - } - --depth_limit; - auto mid = mystl::median(*(first), *(first + (last - first) / 2), - *(last - 1)); - auto cut = mystl::unchecked_partition(first, last, mid); - mystl::intro_sort(cut, last, depth_limit); - last = cut; +// 内省式排序,先进行 quick sort,当分割行为有恶化倾向时,改用 heap sort +template +void intro_sort(RandomIter first, RandomIter last, Size depth_limit) { + while (static_cast(last - first) > kSmallSectionSize) { + if (depth_limit == 0) { // 到达最大分割深度限制 + mystl::partial_sort(first, last, last); // 改用 heap_sort + return; } - } - - // 插入排序辅助函数 unchecked_linear_insert - template - void unchecked_linear_insert(RandomIter last, const T &value) { - auto next = last; + --depth_limit; + auto mid + = mystl::median(*(first), *(first + (last - first) / 2), *(last - 1)); + auto cut = mystl::unchecked_partition(first, last, mid); + mystl::intro_sort(cut, last, depth_limit); + last = cut; + } +} + +// 插入排序辅助函数 unchecked_linear_insert +template +void unchecked_linear_insert(RandomIter last, const T& value) { + auto next = last; + --next; + while (value < *next) { + *last = *next; + last = next; --next; - while (value < *next) { - *last = *next; - last = next; - --next; - } - *last = value; } + *last = value; +} - // 插入排序函数 unchecked_insertion_sort - template - void unchecked_insertion_sort(RandomIter first, RandomIter last) { - for (auto i = first; i != last; ++i) { - mystl::unchecked_linear_insert(i, *i); - } +// 插入排序函数 unchecked_insertion_sort +template +void unchecked_insertion_sort(RandomIter first, RandomIter last) { + for (auto i = first; i != last; ++i) { + mystl::unchecked_linear_insert(i, *i); } +} - // 插入排序函数 insertion_sort - template - void insertion_sort(RandomIter first, RandomIter last) { - if (first == last) - return; - for (auto i = first + 1; i != last; ++i) { - auto value = *i; - if (value < *first) { - mystl::copy_backward(first, i, i + 1); - *first = value; - } - else { - mystl::unchecked_linear_insert(i, value); - } - } +// 插入排序函数 insertion_sort +template +void insertion_sort(RandomIter first, RandomIter last) { + if (first == last) { + return; } - - // 最终插入排序函数 final_insertion_sort - template - void final_insertion_sort(RandomIter first, RandomIter last) { - if (static_cast(last - first) > kSmallSectionSize) { - mystl::insertion_sort(first, first + kSmallSectionSize); - mystl::unchecked_insertion_sort(first + kSmallSectionSize, last); + for (auto i = first + 1; i != last; ++i) { + auto value = *i; + if (value < *first) { + mystl::copy_backward(first, i, i + 1); + *first = value; } else { - mystl::insertion_sort(first, last); + mystl::unchecked_linear_insert(i, value); } } +} - template - void sort(RandomIter first, RandomIter last) { - if (first != last) { - // 内省式排序,将区间分为一个个小区间,然后对整体进行插入排序 - mystl::intro_sort(first, last, slg2(last - first) * 2); - mystl::final_insertion_sort(first, last); - } +// 最终插入排序函数 final_insertion_sort +template +void final_insertion_sort(RandomIter first, RandomIter last) { + if (static_cast(last - first) > kSmallSectionSize) { + mystl::insertion_sort(first, first + kSmallSectionSize); + mystl::unchecked_insertion_sort(first + kSmallSectionSize, last); } - - // 重载版本使用函数对象 comp 代替比较操作 - // 分割函数 unchecked_partition - template - RandomIter unchecked_partition(RandomIter first, RandomIter last, - const T &pivot, Compared comp) { - while (true) { - while (comp(*first, pivot)) - ++first; - --last; - while (comp(pivot, *last)) - --last; - if (!(first < last)) - return first; - mystl::iter_swap(first, last); - ++first; - } + else { + mystl::insertion_sort(first, last); } +} - // 内省式排序,先进行 quick sort,当分割行为有恶化倾向时,改用 heap sort - template - void intro_sort(RandomIter first, RandomIter last, Size depth_limit, - Compared comp) { - while (static_cast(last - first) > kSmallSectionSize) { - if (depth_limit == 0) { // 到达最大分割深度限制 - mystl::partial_sort(first, last, last, comp); // 改用 heap_sort - return; - } - --depth_limit; - auto mid = mystl::median(*(first), *(first + (last - first) / 2), - *(last - 1)); - auto cut = mystl::unchecked_partition(first, last, mid, comp); - mystl::intro_sort(cut, last, depth_limit, comp); - last = cut; - } +template +void sort(RandomIter first, RandomIter last) { + if (first != last) { + // 内省式排序,将区间分为一个个小区间,然后对整体进行插入排序 + mystl::intro_sort(first, last, slg2(last - first) * 2); + mystl::final_insertion_sort(first, last); } +} - // 插入排序辅助函数 unchecked_linear_insert - template - void unchecked_linear_insert(RandomIter last, const T &value, - Compared comp) { - auto next = last; - --next; - while (comp(value, *next)) { // 从尾部开始寻找第一个可插入位置 - *last = *next; - last = next; - --next; +// 重载版本使用函数对象 comp 代替比较操作 +// 分割函数 unchecked_partition +template +RandomIter unchecked_partition(RandomIter first, RandomIter last, + const T& pivot, Compared comp) { + while (true) { + while (comp(*first, pivot)) { + ++first; } - *last = value; - } - - // 插入排序函数 unchecked_insertion_sort - template - void unchecked_insertion_sort(RandomIter first, RandomIter last, - Compared comp) { - for (auto i = first; i != last; ++i) { - mystl::unchecked_linear_insert(i, *i, comp); + --last; + while (comp(pivot, *last)) { + --last; + } + if (!(first < last)) { + return first; } + mystl::iter_swap(first, last); + ++first; } +} - // 插入排序函数 insertion_sort - template - void insertion_sort(RandomIter first, RandomIter last, Compared comp) { - if (first == last) +// 内省式排序,先进行 quick sort,当分割行为有恶化倾向时,改用 heap sort +template +void intro_sort(RandomIter first, RandomIter last, Size depth_limit, + Compared comp) { + while (static_cast(last - first) > kSmallSectionSize) { + if (depth_limit == 0) { // 到达最大分割深度限制 + mystl::partial_sort(first, last, last, comp); // 改用 heap_sort return; - for (auto i = first + 1; i != last; ++i) { - auto value = *i; - if (comp(value, *first)) { - mystl::copy_backward(first, i, i + 1); - *first = value; - } - else { - mystl::unchecked_linear_insert(i, value, comp); - } } + --depth_limit; + auto mid + = mystl::median(*(first), *(first + (last - first) / 2), *(last - 1)); + auto cut = mystl::unchecked_partition(first, last, mid, comp); + mystl::intro_sort(cut, last, depth_limit, comp); + last = cut; + } +} + +// 插入排序辅助函数 unchecked_linear_insert +template +void unchecked_linear_insert(RandomIter last, const T& value, Compared comp) { + auto next = last; + --next; + while (comp(value, *next)) { // 从尾部开始寻找第一个可插入位置 + *last = *next; + last = next; + --next; } + *last = value; +} - // 最终插入排序函数 final_insertion_sort - template - void final_insertion_sort(RandomIter first, RandomIter last, +// 插入排序函数 unchecked_insertion_sort +template +void unchecked_insertion_sort(RandomIter first, RandomIter last, Compared comp) { - if (static_cast(last - first) > kSmallSectionSize) { - mystl::insertion_sort(first, first + kSmallSectionSize, comp); - mystl::unchecked_insertion_sort(first + kSmallSectionSize, last, - comp); - } - else { - mystl::insertion_sort(first, last, comp); - } + for (auto i = first; i != last; ++i) { + mystl::unchecked_linear_insert(i, *i, comp); } +} - template - void sort(RandomIter first, RandomIter last, Compared comp) { - if (first != last) { - // 内省式排序,将区间分为一个个小区间,然后对整体进行插入排序 - mystl::intro_sort(first, last, slg2(last - first) * 2, comp); - mystl::final_insertion_sort(first, last, comp); - } +// 插入排序函数 insertion_sort +template +void insertion_sort(RandomIter first, RandomIter last, Compared comp) { + if (first == last) { + return; } - - /*****************************************************************************************/ - // nth_element - // 对序列重排,使得所有小于第 n - // 个元素的元素出现在它的前面,大于它的出现在它的后面 - /*****************************************************************************************/ - template - void nth_element(RandomIter first, RandomIter nth, RandomIter last) { - if (nth == last) - return; - while (last - first > 3) { - auto cut = mystl::unchecked_partition( - first, last, - mystl::median(*first, *(first + (last - first) / 2), - *(last - 1))); - if (cut <= nth) // 如果 nth 位于右段 - first = cut; // 对右段进行分割 - else - last = cut; // 对左段进行分割 + for (auto i = first + 1; i != last; ++i) { + auto value = *i; + if (comp(value, *first)) { + mystl::copy_backward(first, i, i + 1); + *first = value; + } + else { + mystl::unchecked_linear_insert(i, value, comp); } - mystl::insertion_sort(first, last); } +} - // 重载版本使用函数对象 comp 代替比较操作 - template - void nth_element(RandomIter first, RandomIter nth, RandomIter last, - Compared comp) { - if (nth == last) - return; - while (last - first > 3) { - auto cut = mystl::unchecked_partition( - first, last, - mystl::median(*first, *(first + (last - first) / 2), - *(last - 1)), - comp); - if (cut <= nth) // 如果 nth 位于右段 - first = cut; // 对右段进行分割 - else - last = cut; // 对左段进行分割 - } +// 最终插入排序函数 final_insertion_sort +template +void final_insertion_sort(RandomIter first, RandomIter last, Compared comp) { + if (static_cast(last - first) > kSmallSectionSize) { + mystl::insertion_sort(first, first + kSmallSectionSize, comp); + mystl::unchecked_insertion_sort(first + kSmallSectionSize, last, comp); + } + else { mystl::insertion_sort(first, last, comp); } - - /*****************************************************************************************/ - // unique_copy - // 从[first, last)中将元素复制到 result - // 上,序列必须有序,如果有重复的元素,只会复制一次 - /*****************************************************************************************/ - // unique_copy_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter unique_copy_dispatch(InputIter first, InputIter last, - ForwardIter result, forward_iterator_tag) { - *result = *first; - while (++first != last) { - if (*result != *first) - *++result = *first; - } - return ++result; - } - - // unique_copy_dispatch 的 output_iterator_tag 版本 - // 由于 output iterator 只能进行只读操作,所以不能有 *result != *first - // 这样的判断 - template - OutputIter unique_copy_dispatch(InputIter first, InputIter last, - OutputIter result, output_iterator_tag) { - auto value = *first; - *result = value; - while (++first != last) { - if (value != *first) { - value = *first; - *++result = value; - } +} + +template +void sort(RandomIter first, RandomIter last, Compared comp) { + if (first != last) { + // 内省式排序,将区间分为一个个小区间,然后对整体进行插入排序 + mystl::intro_sort(first, last, slg2(last - first) * 2, comp); + mystl::final_insertion_sort(first, last, comp); + } +} + +/*****************************************************************************************/ +// nth_element +// 对序列重排,使得所有小于第 n +// 个元素的元素出现在它的前面,大于它的出现在它的后面 +/*****************************************************************************************/ +template +void nth_element(RandomIter first, RandomIter nth, RandomIter last) { + if (nth == last) { + return; + } + while (last - first > 3) { + auto cut = mystl::unchecked_partition( + first, last, + mystl::median(*first, *(first + (last - first) / 2), *(last - 1))); + if (cut <= nth) { // 如果 nth 位于右段 + first = cut; // 对右段进行分割 } - return ++result; - } - - template - OutputIter unique_copy(InputIter first, InputIter last, OutputIter result) { - if (first == last) - return result; - return mystl::unique_copy_dispatch(first, last, result, - iterator_category(result)); - } - - // 重载版本使用函数对象 comp 代替比较操作 - // unique_copy_dispatch 的 forward_iterator_tag 版本 - template - ForwardIter unique_copy_dispatch(InputIter first, InputIter last, - ForwardIter result, forward_iterator_tag, - Compared comp) { - *result = *first; - while (++first != last) { - if (!comp(*result, *first)) - *++result = *first; - } - return ++result; - } - - // unique_copy_dispatch 的 output_iterator_tag 版本 - // 由于 output iterator 只能进行只读操作,所以不能有 *result != *first - // 这样的判断 - template - OutputIter unique_copy_dispatch(InputIter first, InputIter last, - OutputIter result, output_iterator_tag, - Compared comp) { - auto value = *first; - *result = value; - while (++first != last) { - if (!comp(value, *first)) { - value = *first; - *++result = value; - } + else { + last = cut; // 对左段进行分割 } - return ++result; } + mystl::insertion_sort(first, last); +} - template - OutputIter unique_copy(InputIter first, InputIter last, OutputIter result, - Compared comp) { - if (first == last) - return result; - return mystl::unique_copy_dispatch(first, last, result, - iterator_category(result), comp); +// 重载版本使用函数对象 comp 代替比较操作 +template +void nth_element(RandomIter first, RandomIter nth, RandomIter last, + Compared comp) { + if (nth == last) { + return; } - - /*****************************************************************************************/ - // unique - // 移除[first, last)内重复的元素,序列必须有序,和 remove - // 类似,它也不能真正的删除重复元素 - /*****************************************************************************************/ - template - ForwardIter unique(ForwardIter first, ForwardIter last) { - first = mystl::adjacent_find(first, last); - return mystl::unique_copy(first, last, first); + while (last - first > 3) { + auto cut = mystl::unchecked_partition( + first, last, + mystl::median(*first, *(first + (last - first) / 2), *(last - 1)), + comp); + if (cut <= nth) { // 如果 nth 位于右段 + first = cut; // 对右段进行分割 + } + else { + last = cut; // 对左段进行分割 + } + } + mystl::insertion_sort(first, last, comp); +} + +/*****************************************************************************************/ +// unique_copy +// 从[first, last)中将元素复制到 result +// 上,序列必须有序,如果有重复的元素,只会复制一次 +/*****************************************************************************************/ +// unique_copy_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter unique_copy_dispatch(InputIter first, InputIter last, + ForwardIter result, forward_iterator_tag) { + *result = *first; + while (++first != last) { + if (*result != *first) { + *++result = *first; + } + } + return ++result; +} + +// unique_copy_dispatch 的 output_iterator_tag 版本 +// 由于 output iterator 只能进行只读操作,所以不能有 *result != *first +// 这样的判断 +template +OutputIter unique_copy_dispatch(InputIter first, InputIter last, + OutputIter result, output_iterator_tag) { + auto value = *first; + *result = value; + while (++first != last) { + if (value != *first) { + value = *first; + *++result = value; + } + } + return ++result; +} + +template +OutputIter unique_copy(InputIter first, InputIter last, OutputIter result) { + if (first == last) { + return result; } - - // 重载版本使用函数对象 comp 代替比较操作 - template - ForwardIter unique(ForwardIter first, ForwardIter last, Compared comp) { - first = mystl::adjacent_find(first, last, comp); - return mystl::unique_copy(first, last, first, comp); + return mystl::unique_copy_dispatch(first, last, result, + iterator_category(result)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// unique_copy_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +unique_copy_dispatch(InputIter first, InputIter last, ForwardIter result, + forward_iterator_tag, Compared comp) { + *result = *first; + while (++first != last) { + if (!comp(*result, *first)) { + *++result = *first; + } + } + return ++result; +} + +// unique_copy_dispatch 的 output_iterator_tag 版本 +// 由于 output iterator 只能进行只读操作,所以不能有 *result != *first +// 这样的判断 +template +OutputIter +unique_copy_dispatch(InputIter first, InputIter last, OutputIter result, + output_iterator_tag, Compared comp) { + auto value = *first; + *result = value; + while (++first != last) { + if (!comp(value, *first)) { + value = *first; + *++result = value; + } + } + return ++result; +} + +template +OutputIter +unique_copy(InputIter first, InputIter last, OutputIter result, Compared comp) { + if (first == last) { + return result; } - -}; - -#endif /* _ALGO_ */ + return mystl::unique_copy_dispatch(first, last, result, + iterator_category(result), comp); +} + +/*****************************************************************************************/ +// unique +// 移除[first, last)内重复的元素,序列必须有序,和 remove +// 类似,它也不能真正的删除重复元素 +/*****************************************************************************************/ +template +ForwardIter unique(ForwardIter first, ForwardIter last) { + first = mystl::adjacent_find(first, last); + return mystl::unique_copy(first, last, first); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter unique(ForwardIter first, ForwardIter last, Compared comp) { + first = mystl::adjacent_find(first, last, comp); + return mystl::unique_copy(first, last, first, comp); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_ALGO */ diff --git a/src/libcxx/include/algobase b/src/libcxx/include/algobase index 61f41db03..fffed7122 100644 --- a/src/libcxx/include/algobase +++ b/src/libcxx/include/algobase @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// algobase for Simple-XX/SimpleKernel. - -#ifndef _ALGOBASE_ -#define _ALGOBASE_ +/** + * @file algobase + * @brief stl algobase 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_ALGOBASE +#define SIMPLEKERNEL_ALGOBASE // 这个头文件包含了 std 的基本算法 @@ -16,459 +27,468 @@ namespace mystl { #ifdef max -#pragma message("#undefing marco max") -#undef max -#endif // max +# pragma message("#undefing marco max") +# undef max +#endif // max #ifdef min -#pragma message("#undefing marco min") -#undef min -#endif // min - - /*****************************************************************************************/ - // max - // 取二者中的较大值,语义相等时保证返回第一个参数 - /*****************************************************************************************/ - template - const T &max(const T &lhs, const T &rhs) { - return lhs < rhs ? rhs : lhs; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - const T &max(const T &lhs, const T &rhs, Compare comp) { - return comp(lhs, rhs) ? rhs : lhs; - } - - /*****************************************************************************************/ - // min - // 取二者中的较小值,语义相等时保证返回第一个参数 - /*****************************************************************************************/ - template - const T &min(const T &lhs, const T &rhs) { - return rhs < lhs ? rhs : lhs; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - const T &min(const T &lhs, const T &rhs, Compare comp) { - return comp(rhs, lhs) ? rhs : lhs; - } - - /*****************************************************************************************/ - // iter_swap - // 将两个迭代器所指对象对调 - /*****************************************************************************************/ - template - void iter_swap(FIter1 lhs, FIter2 rhs) { - mystl::swap(*lhs, *rhs); - } - - /*****************************************************************************************/ - // copy - // 把 [first, last)区间内的元素拷贝到 [result, result + (last - first))内 - /*****************************************************************************************/ - // input_iterator_tag 版本 - template - OutputIter unchecked_copy_cat(InputIter first, InputIter last, - OutputIter result, - mystl::input_iterator_tag) { - for (; first != last; ++first, ++result) { - *result = *first; - } - return result; - } - - // ramdom_access_iterator_tag 版本 - template - OutputIter unchecked_copy_cat(RandomIter first, RandomIter last, - OutputIter result, - mystl::random_access_iterator_tag) { - for (auto n = last - first; n > 0; --n, ++first, ++result) { - *result = *first; - } - return result; - } - - template - OutputIter unchecked_copy(InputIter first, InputIter last, - OutputIter result) { - return unchecked_copy_cat(first, last, result, - iterator_category(first)); - } - - // 为 trivially_copy_assignable 类型提供特化版本 - template - typename std::enable_if< - std::is_same::type, Up>::value && - std::is_trivially_copy_assignable::value, - Up *>::type - unchecked_copy(Tp *first, Tp *last, Up *result) { - const auto n = static_cast(last - first); - if (n != 0) - std::memmove(result, first, n * sizeof(Up)); - return result + n; - } - - template - OutputIter copy(InputIter first, InputIter last, OutputIter result) { - return unchecked_copy(first, last, result); - } - - /*****************************************************************************************/ - // copy_backward - // 将 [first, last)区间内的元素拷贝到 [result - (last - first), result)内 - /*****************************************************************************************/ - // unchecked_copy_backward_cat 的 bidirectional_iterator_tag 版本 - template - BidirectionalIter2 unchecked_copy_backward_cat( - BidirectionalIter1 first, BidirectionalIter1 last, - BidirectionalIter2 result, mystl::bidirectional_iterator_tag) { - while (first != last) - *--result = *--last; - return result; - } - - // unchecked_copy_backward_cat 的 random_access_iterator_tag 版本 - template - BidirectionalIter2 unchecked_copy_backward_cat( - BidirectionalIter1 first, BidirectionalIter1 last, - BidirectionalIter2 result, mystl::random_access_iterator_tag) { - for (auto n = last - first; n > 0; --n) - *--result = *--last; - return result; - } - - template - BidirectionalIter2 unchecked_copy_backward(BidirectionalIter1 first, - BidirectionalIter1 last, - BidirectionalIter2 result) { - return unchecked_copy_backward_cat(first, last, result, - iterator_category(first)); - } - - // 为 trivially_copy_assignable 类型提供特化版本 - template - typename std::enable_if< - std::is_same::type, Up>::value && - std::is_trivially_copy_assignable::value, - Up *>::type - unchecked_copy_backward(Tp *first, Tp *last, Up *result) { - const auto n = static_cast(last - first); - if (n != 0) { - result -= n; - std::memmove(result, first, n * sizeof(Up)); - } - return result; - } - - template - BidirectionalIter2 copy_backward(BidirectionalIter1 first, - BidirectionalIter1 last, - BidirectionalIter2 result) { - return unchecked_copy_backward(first, last, result); - } - - /*****************************************************************************************/ - // copy_if - // 把[first, last)内满足一元操作 unary_pred 的元素拷贝到以 result - // 为起始的位置上 - /*****************************************************************************************/ - template - OutputIter copy_if(InputIter first, InputIter last, OutputIter result, - UnaryPredicate unary_pred) { - for (; first != last; ++first) { - if (unary_pred(*first)) - *result++ = *first; - } - return result; - } - - /*****************************************************************************************/ - // copy_n - // 把 [first, first + n)区间上的元素拷贝到 [result, result + n)上 - // 返回一个 pair 分别指向拷贝结束的尾部 - /*****************************************************************************************/ - template - mystl::pair - unchecked_copy_n(InputIter first, Size n, OutputIter result, - mystl::input_iterator_tag) { - for (; n > 0; --n, ++first, ++result) { - *result = *first; - } - return mystl::pair(first, result); - } - - template - mystl::pair - unchecked_copy_n(RandomIter first, Size n, OutputIter result, - mystl::random_access_iterator_tag) { - auto last = first + n; - return mystl::pair( - last, mystl::copy(first, last, result)); - } - - template - mystl::pair copy_n(InputIter first, Size n, - OutputIter result) { - return unchecked_copy_n(first, n, result, iterator_category(first)); - } - - /*****************************************************************************************/ - // move - // 把 [first, last)区间内的元素移动到 [result, result + (last - first))内 - /*****************************************************************************************/ - // input_iterator_tag 版本 - template - OutputIter unchecked_move_cat(InputIter first, InputIter last, - OutputIter result, - mystl::input_iterator_tag) { - for (; first != last; ++first, ++result) { - *result = mystl::move(*first); - } - return result; - } - - // ramdom_access_iterator_tag 版本 - template - OutputIter unchecked_move_cat(RandomIter first, RandomIter last, - OutputIter result, - mystl::random_access_iterator_tag) { - for (auto n = last - first; n > 0; --n, ++first, ++result) { - *result = mystl::move(*first); +# pragma message("#undefing marco min") +# undef min +#endif // min + +/*****************************************************************************************/ +// max +// 取二者中的较大值,语义相等时保证返回第一个参数 +/*****************************************************************************************/ +template +const T& max(const T& lhs, const T& rhs) { + return lhs < rhs ? rhs : lhs; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +const T& max(const T& lhs, const T& rhs, Compare comp) { + return comp(lhs, rhs) ? rhs : lhs; +} + +/*****************************************************************************************/ +// min +// 取二者中的较小值,语义相等时保证返回第一个参数 +/*****************************************************************************************/ +template +const T& min(const T& lhs, const T& rhs) { + return rhs < lhs ? rhs : lhs; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +const T& min(const T& lhs, const T& rhs, Compare comp) { + return comp(rhs, lhs) ? rhs : lhs; +} + +/*****************************************************************************************/ +// iter_swap +// 将两个迭代器所指对象对调 +/*****************************************************************************************/ +template +void iter_swap(FIter1 lhs, FIter2 rhs) { + mystl::swap(*lhs, *rhs); +} + +/*****************************************************************************************/ +// copy +// 把 [first, last)区间内的元素拷贝到 [result, result + (last - first))内 +/*****************************************************************************************/ +// input_iterator_tag 版本 +template +OutputIter unchecked_copy_cat(InputIter first, InputIter last, + OutputIter result, mystl::input_iterator_tag) { + for (; first != last; ++first, ++result) { + *result = *first; + } + return result; +} + +// ramdom_access_iterator_tag 版本 +template +OutputIter +unchecked_copy_cat(RandomIter first, RandomIter last, OutputIter result, + mystl::random_access_iterator_tag) { + for (auto n = last - first; n > 0; --n, ++first, ++result) { + *result = *first; + } + return result; +} + +template +OutputIter unchecked_copy(InputIter first, InputIter last, OutputIter result) { + return unchecked_copy_cat(first, last, result, iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value + && std::is_trivially_copy_assignable::value, + Up*>::type +unchecked_copy(Tp* first, Tp* last, Up* result) { + const auto n = static_cast(last - first); + if (n != 0) { + std::memmove(result, first, n * sizeof(Up)); + } + return result + n; +} + +template +OutputIter copy(InputIter first, InputIter last, OutputIter result) { + return unchecked_copy(first, last, result); +} + +/*****************************************************************************************/ +// copy_backward +// 将 [first, last)区间内的元素拷贝到 [result - (last - first), result)内 +/*****************************************************************************************/ +// unchecked_copy_backward_cat 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter2 +unchecked_copy_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result, + mystl::bidirectional_iterator_tag) { + while (first != last) { + *--result = *--last; + } + return result; +} + +// unchecked_copy_backward_cat 的 random_access_iterator_tag 版本 +template +BidirectionalIter2 +unchecked_copy_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result, + mystl::random_access_iterator_tag) { + for (auto n = last - first; n > 0; --n) { + *--result = *--last; + } + return result; +} + +template +BidirectionalIter2 +unchecked_copy_backward(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result) { + return unchecked_copy_backward_cat(first, last, result, + iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value + && std::is_trivially_copy_assignable::value, + Up*>::type +unchecked_copy_backward(Tp* first, Tp* last, Up* result) { + const auto n = static_cast(last - first); + if (n != 0) { + result -= n; + std::memmove(result, first, n * sizeof(Up)); + } + return result; +} + +template +BidirectionalIter2 +copy_backward(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result) { + return unchecked_copy_backward(first, last, result); +} + +/*****************************************************************************************/ +// copy_if +// 把[first, last)内满足一元操作 unary_pred 的元素拷贝到以 result +// 为起始的位置上 +/*****************************************************************************************/ +template +OutputIter copy_if(InputIter first, InputIter last, OutputIter result, + UnaryPredicate unary_pred) { + for (; first != last; ++first) { + if (unary_pred(*first)) { + *result++ = *first; } - return result; - } - - template - OutputIter unchecked_move(InputIter first, InputIter last, - OutputIter result) { - return unchecked_move_cat(first, last, result, - iterator_category(first)); - } - - // 为 trivially_copy_assignable 类型提供特化版本 - template - typename std::enable_if< - std::is_same::type, Up>::value && - std::is_trivially_move_assignable::value, - Up *>::type - unchecked_move(Tp *first, Tp *last, Up *result) { - const size_t n = static_cast(last - first); - if (n != 0) - std::memmove(result, first, n * sizeof(Up)); - return result + n; - } - - template - OutputIter move(InputIter first, InputIter last, OutputIter result) { - return unchecked_move(first, last, result); - } - - /*****************************************************************************************/ - // move_backward - // 将 [first, last)区间内的元素移动到 [result - (last - first), result)内 - /*****************************************************************************************/ - // bidirectional_iterator_tag 版本 - template - BidirectionalIter2 unchecked_move_backward_cat( - BidirectionalIter1 first, BidirectionalIter1 last, - BidirectionalIter2 result, mystl::bidirectional_iterator_tag) { - while (first != last) - *--result = mystl::move(*--last); - return result; - } - - // random_access_iterator_tag 版本 - template - RandomIter2 unchecked_move_backward_cat(RandomIter1 first, RandomIter1 last, - RandomIter2 result, - mystl::random_access_iterator_tag) { - for (auto n = last - first; n > 0; --n) - *--result = mystl::move(*--last); - return result; } - - template - BidirectionalIter2 unchecked_move_backward(BidirectionalIter1 first, - BidirectionalIter1 last, - BidirectionalIter2 result) { - return unchecked_move_backward_cat(first, last, result, - iterator_category(first)); - } - - // 为 trivially_copy_assignable 类型提供特化版本 - template - typename std::enable_if< - std::is_same::type, Up>::value && - std::is_trivially_move_assignable::value, - Up *>::type - unchecked_move_backward(Tp *first, Tp *last, Up *result) { - const size_t n = static_cast(last - first); - if (n != 0) { - result -= n; - std::memmove(result, first, n * sizeof(Up)); + return result; +} + +/*****************************************************************************************/ +// copy_n +// 把 [first, first + n)区间上的元素拷贝到 [result, result + n)上 +// 返回一个 pair 分别指向拷贝结束的尾部 +/*****************************************************************************************/ +template +mystl::pair +unchecked_copy_n(InputIter first, Size n, OutputIter result, + mystl::input_iterator_tag) { + for (; n > 0; --n, ++first, ++result) { + *result = *first; + } + return mystl::pair(first, result); +} + +template +mystl::pair +unchecked_copy_n(RandomIter first, Size n, OutputIter result, + mystl::random_access_iterator_tag) { + auto last = first + n; + return mystl::pair(last, mystl::copy(first, last, + result)); +} + +template +mystl::pair +copy_n(InputIter first, Size n, OutputIter result) { + return unchecked_copy_n(first, n, result, iterator_category(first)); +} + +/*****************************************************************************************/ +// move +// 把 [first, last)区间内的元素移动到 [result, result + (last - first))内 +/*****************************************************************************************/ +// input_iterator_tag 版本 +template +OutputIter unchecked_move_cat(InputIter first, InputIter last, + OutputIter result, mystl::input_iterator_tag) { + for (; first != last; ++first, ++result) { + *result = mystl::move(*first); + } + return result; +} + +// ramdom_access_iterator_tag 版本 +template +OutputIter +unchecked_move_cat(RandomIter first, RandomIter last, OutputIter result, + mystl::random_access_iterator_tag) { + for (auto n = last - first; n > 0; --n, ++first, ++result) { + *result = mystl::move(*first); + } + return result; +} + +template +OutputIter unchecked_move(InputIter first, InputIter last, OutputIter result) { + return unchecked_move_cat(first, last, result, iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value + && std::is_trivially_move_assignable::value, + Up*>::type +unchecked_move(Tp* first, Tp* last, Up* result) { + const size_t n = static_cast(last - first); + if (n != 0) { + std::memmove(result, first, n * sizeof(Up)); + } + return result + n; +} + +template +OutputIter move(InputIter first, InputIter last, OutputIter result) { + return unchecked_move(first, last, result); +} + +/*****************************************************************************************/ +// move_backward +// 将 [first, last)区间内的元素移动到 [result - (last - first), result)内 +/*****************************************************************************************/ +// bidirectional_iterator_tag 版本 +template +BidirectionalIter2 +unchecked_move_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result, + mystl::bidirectional_iterator_tag) { + while (first != last) { + *--result = mystl::move(*--last); + } + return result; +} + +// random_access_iterator_tag 版本 +template +RandomIter2 unchecked_move_backward_cat(RandomIter1 first, RandomIter1 last, + RandomIter2 result, + mystl::random_access_iterator_tag) { + for (auto n = last - first; n > 0; --n) { + *--result = mystl::move(*--last); + } + return result; +} + +template +BidirectionalIter2 +unchecked_move_backward(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result) { + return unchecked_move_backward_cat(first, last, result, + iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value + && std::is_trivially_move_assignable::value, + Up*>::type +unchecked_move_backward(Tp* first, Tp* last, Up* result) { + const size_t n = static_cast(last - first); + if (n != 0) { + result -= n; + std::memmove(result, first, n * sizeof(Up)); + } + return result; +} + +template +BidirectionalIter2 +move_backward(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result) { + return unchecked_move_backward(first, last, result); +} + +/*****************************************************************************************/ +// equal +// 比较第一序列在 [first, last)区间上的元素值是否和第二序列相等 +/*****************************************************************************************/ +template +bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2) { + for (; first1 != last1; ++first1, ++first2) { + if (*first1 != *first2) { + return false; } - return result; } + return true; +} - template - BidirectionalIter2 move_backward(BidirectionalIter1 first, - BidirectionalIter1 last, - BidirectionalIter2 result) { - return unchecked_move_backward(first, last, result); - } - - /*****************************************************************************************/ - // equal - // 比较第一序列在 [first, last)区间上的元素值是否和第二序列相等 - /*****************************************************************************************/ - template - bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2) { - for (; first1 != last1; ++first1, ++first2) { - if (*first1 != *first2) - return false; +// 重载版本使用函数对象 comp 代替比较操作 +template +bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, + Compared comp) { + for (; first1 != last1; ++first1, ++first2) { + if (!comp(*first1, *first2)) { + return false; } - return true; } - - // 重载版本使用函数对象 comp 代替比较操作 - template - bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, - Compared comp) { - for (; first1 != last1; ++first1, ++first2) { - if (!comp(*first1, *first2)) - return false; + return true; +} + +/*****************************************************************************************/ +// fill_n +// 从 first 位置开始填充 n 个值 +/*****************************************************************************************/ +template +OutputIter unchecked_fill_n(OutputIter first, Size n, const T& value) { + for (; n > 0; --n, ++first) { + *first = value; + } + return first; +} + +// 为 one-byte 类型提供特化版本 +template +typename std::enable_if::value && sizeof(Tp) == 1 + && !std::is_same::value + && std::is_integral::value && sizeof(Up) == 1, + Tp*>::type +unchecked_fill_n(Tp* first, Size n, Up value) { + if (n > 0) { + std::memset(first, (unsigned char)value, (size_t)(n)); + } + return first + n; +} + +template +OutputIter fill_n(OutputIter first, Size n, const T& value) { + return unchecked_fill_n(first, n, value); +} + +/*****************************************************************************************/ +// fill +// 为 [first, last)区间内的所有元素填充新值 +/*****************************************************************************************/ +template +void fill_cat(ForwardIter first, ForwardIter last, const T& value, + mystl::forward_iterator_tag) { + for (; first != last; ++first) { + *first = value; + } +} + +template +void fill_cat(RandomIter first, RandomIter last, const T& value, + mystl::random_access_iterator_tag) { + fill_n(first, last - first, value); +} + +template +void fill(ForwardIter first, ForwardIter last, const T& value) { + fill_cat(first, last, value, iterator_category(first)); +} + +/*****************************************************************************************/ +// lexicographical_compare +// 以字典序排列对两个序列进行比较,当在某个位置发现第一组不相等元素时,有下列几种情况: +// (1)如果第一序列的元素较小,返回 true ,否则返回 false +// (2)如果到达 last1 而尚未到达 last2 返回 true +// (3)如果到达 last2 而尚未到达 last1 返回 false +// (4)如果同时到达 last1 和 last2 返回 false +/*****************************************************************************************/ +template +bool lexicographical_compare(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2) { + for (; first1 != last1 && first2 != last2; ++first1, ++first2) { + if (*first1 < *first2) { + return true; } - return true; - } - - /*****************************************************************************************/ - // fill_n - // 从 first 位置开始填充 n 个值 - /*****************************************************************************************/ - template - OutputIter unchecked_fill_n(OutputIter first, Size n, const T &value) { - for (; n > 0; --n, ++first) { - *first = value; + if (*first2 < *first1) { + return false; } - return first; } - - // 为 one-byte 类型提供特化版本 - template - typename std::enable_if::value && sizeof(Tp) == 1 && - !std::is_same::value && - std::is_integral::value && sizeof(Up) == 1, - Tp *>::type - unchecked_fill_n(Tp *first, Size n, Up value) { - if (n > 0) { - std::memset(first, (unsigned char)value, (size_t)(n)); + return first1 == last1 && first2 != last2; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool lexicographical_compare(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + Compred comp) { + for (; first1 != last1 && first2 != last2; ++first1, ++first2) { + if (comp(*first1, *first2)) { + return true; } - return first + n; - } - - template - OutputIter fill_n(OutputIter first, Size n, const T &value) { - return unchecked_fill_n(first, n, value); - } - - /*****************************************************************************************/ - // fill - // 为 [first, last)区间内的所有元素填充新值 - /*****************************************************************************************/ - template - void fill_cat(ForwardIter first, ForwardIter last, const T &value, - mystl::forward_iterator_tag) { - for (; first != last; ++first) { - *first = value; - } - } - - template - void fill_cat(RandomIter first, RandomIter last, const T &value, - mystl::random_access_iterator_tag) { - fill_n(first, last - first, value); - } - - template - void fill(ForwardIter first, ForwardIter last, const T &value) { - fill_cat(first, last, value, iterator_category(first)); - } - - /*****************************************************************************************/ - // lexicographical_compare - // 以字典序排列对两个序列进行比较,当在某个位置发现第一组不相等元素时,有下列几种情况: - // (1)如果第一序列的元素较小,返回 true ,否则返回 false - // (2)如果到达 last1 而尚未到达 last2 返回 true - // (3)如果到达 last2 而尚未到达 last1 返回 false - // (4)如果同时到达 last1 和 last2 返回 false - /*****************************************************************************************/ - template - bool lexicographical_compare(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2) { - for (; first1 != last1 && first2 != last2; ++first1, ++first2) { - if (*first1 < *first2) - return true; - if (*first2 < *first1) - return false; - } - return first1 == last1 && first2 != last2; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - bool lexicographical_compare(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - Compred comp) { - for (; first1 != last1 && first2 != last2; ++first1, ++first2) { - if (comp(*first1, *first2)) - return true; - if (comp(*first2, *first1)) - return false; - } - return first1 == last1 && first2 != last2; - } - - // 针对 const unsigned char* 的特化版本 - bool lexicographical_compare(const unsigned char *first1, - const unsigned char *last1, - const unsigned char *first2, - const unsigned char *last2) { - const auto len1 = last1 - first1; - const auto len2 = last2 - first2; - // 先比较相同长度的部分 - const auto result = std::memcmp(first1, first2, mystl::min(len1, len2)); - // 若相等,长度较长的比较大 - return result != 0 ? result < 0 : len1 < len2; - } - - /*****************************************************************************************/ - // mismatch - // 平行比较两个序列,找到第一处失配的元素,返回一对迭代器,分别指向两个序列中失配的元素 - /*****************************************************************************************/ - template - mystl::pair - mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2) { - while (first1 != last1 && *first1 == *first2) { - ++first1; - ++first2; + if (comp(*first2, *first1)) { + return false; } - return mystl::pair(first1, first2); } - - // 重载版本使用函数对象 comp 代替比较操作 - template - mystl::pair - mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2, - Compred comp) { - while (first1 != last1 && comp(*first1, *first2)) { - ++first1; - ++first2; - } - return mystl::pair(first1, first2); - } - -}; - -#endif /* _ALGOBASE_ */ + return first1 == last1 && first2 != last2; +} + +// 针对 const unsigned char* 的特化版本 +bool lexicographical_compare(const unsigned char* first1, + const unsigned char* last1, + const unsigned char* first2, + const unsigned char* last2) { + const auto len1 = last1 - first1; + const auto len2 = last2 - first2; + // 先比较相同长度的部分 + const auto result = std::memcmp(first1, first2, mystl::min(len1, len2)); + // 若相等,长度较长的比较大 + return result != 0 ? result < 0 : len1 < len2; +} + +/*****************************************************************************************/ +// mismatch +// 平行比较两个序列,找到第一处失配的元素,返回一对迭代器,分别指向两个序列中失配的元素 +/*****************************************************************************************/ +template +mystl::pair +mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2) { + while (first1 != last1 && *first1 == *first2) { + ++first1; + ++first2; + } + return mystl::pair(first1, first2); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +mystl::pair +mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2, Compred comp) { + while (first1 != last1 && comp(*first1, *first2)) { + ++first1; + ++first2; + } + return mystl::pair(first1, first2); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_ALGOBASE */ diff --git a/src/libcxx/include/algorithm b/src/libcxx/include/algorithm index 48767d356..23245af93 100644 --- a/src/libcxx/include/algorithm +++ b/src/libcxx/include/algorithm @@ -1,21 +1,32 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// algorithm for Simple-XX/SimpleKernel. +/** + * @file algorithm + * @brief stl algorithm 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ -#ifndef _ALGORITHM_ -#define _ALGORITHM_ +#ifndef SIMPLEKERNEL_ALGORITHM +#define SIMPLEKERNEL_ALGORITHM // 这个头文件包含了 std 的所有算法,包括基本算法,数值算法,heap 算法,set // 算法和其他算法 -#include "algobase" #include "algo" -#include "set_algo" +#include "algobase" #include "heap_algo" #include "numeric" +#include "set_algo" -namespace mystl {}; +namespace mystl { }; -#endif /* _ALGORITHM_ */ +#endif /* SIMPLEKERNEL_ALGORITHM */ diff --git a/src/libcxx/include/allocator b/src/libcxx/include/allocator index 18dac68c1..8bb266540 100644 --- a/src/libcxx/include/allocator +++ b/src/libcxx/include/allocator @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// allocator for Simple-XX/SimpleKernel. - -#ifndef _ALLOCATOR_ -#define _ALLOCATOR_ +/** + * @file allocator + * @brief stl allocator 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_ALLOCATOR +#define SIMPLEKERNEL_ALLOCATOR // 这个头文件包含一个模板类 // allocator,用于管理内存的分配、释放,对象的构造、析构 @@ -15,94 +26,97 @@ namespace mystl { - // 模板类:allocator - // 模板函数代表数据类型 - template - class allocator { - public: - typedef T value_type; - typedef T * pointer; - typedef const T * const_pointer; - typedef T & reference; - typedef const T & const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - public: - static T *allocate(); - static T *allocate(size_type n); - - static void deallocate(T *ptr); - static void deallocate(T *ptr, size_type n); - - static void construct(T *ptr); - static void construct(T *ptr, const T &value); - static void construct(T *ptr, T &&value); - - template - static void construct(T *ptr, Args &&...args); - - static void destroy(T *ptr); - static void destroy(T *first, T *last); - }; - - template - T *allocator::allocate() { - return static_cast(::operator new(sizeof(T))); - } +// 模板类:allocator +// 模板函数代表数据类型 +template +class allocator { +public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + +public: + static T* allocate(); + static T* allocate(size_type n); + + static void deallocate(T* ptr); + static void deallocate(T* ptr, size_type n); + + static void construct(T* ptr); + static void construct(T* ptr, const T& value); + static void construct(T* ptr, T&& value); - template - T *allocator::allocate(size_type n) { - if (n == 0) - return nullptr; - return static_cast(::operator new(n * sizeof(T))); - } - - template - void allocator::deallocate(T *ptr) { - if (ptr == nullptr) - return; - ::operator delete(ptr); - } - - template - void allocator::deallocate(T *ptr, size_type /*size*/) { - if (ptr == nullptr) - return; - ::operator delete(ptr); - } - - template - void allocator::construct(T *ptr) { - mystl::construct(ptr); - } + template + static void construct(T* ptr, Args&&... args); - template - void allocator::construct(T *ptr, const T &value) { - mystl::construct(ptr, value); - } + static void destroy(T* ptr); + static void destroy(T* first, T* last); +}; - template - void allocator::construct(T *ptr, T &&value) { - mystl::construct(ptr, mystl::move(value)); - } +template +T* allocator::allocate() { + return static_cast(::operator new(sizeof(T))); +} - template - template - void allocator::construct(T *ptr, Args &&...args) { - mystl::construct(ptr, mystl::forward(args)...); +template +T* allocator::allocate(size_type n) { + if (n == 0) { + return nullptr; } + return static_cast(::operator new(n * sizeof(T))); +} - template - void allocator::destroy(T *ptr) { - mystl::destroy(ptr); +template +void allocator::deallocate(T* ptr) { + if (ptr == nullptr) { + return; } + ::operator delete(ptr); +} - template - void allocator::destroy(T *first, T *last) { - mystl::destroy(first, last); +template +void allocator::deallocate(T* ptr, size_type /*size*/) { + if (ptr == nullptr) { + return; } - -}; - -#endif /* _ALLOCATOR_ */ + ::operator delete(ptr); +} + +template +void allocator::construct(T* ptr) { + mystl::construct(ptr); +} + +template +void allocator::construct(T* ptr, const T& value) { + mystl::construct(ptr, value); +} + +template +void allocator::construct(T* ptr, T&& value) { + mystl::construct(ptr, mystl::move(value)); +} + +template +template +void allocator::construct(T* ptr, Args&&... args) { + mystl::construct(ptr, mystl::forward(args)...); +} + +template +void allocator::destroy(T* ptr) { + mystl::destroy(ptr); +} + +template +void allocator::destroy(T* first, T* last) { + mystl::destroy(first, last); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_ALLOCATOR */ diff --git a/src/libcxx/include/astring b/src/libcxx/include/astring index ff4443a5c..c12e19451 100644 --- a/src/libcxx/include/astring +++ b/src/libcxx/include/astring @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// astring for Simple-XX/SimpleKernel. +/** + * @file astring + * @brief stl astring 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ -#ifndef _ASTRING_ -#define _ASTRING_ +#ifndef SIMPLEKERNEL_ASTRING +#define SIMPLEKERNEL_ASTRING // 定义了 string, wstring, u16string, u32string 类型 @@ -13,11 +24,11 @@ namespace mystl { - using string = mystl::basic_string; - using wstring = mystl::basic_string; - using u16string = mystl::basic_string; - using u32string = mystl::basic_string; +using string = mystl::basic_string; +using wstring = mystl::basic_string; +using u16string = mystl::basic_string; +using u32string = mystl::basic_string; -}; +}; // namespace mystl -#endif /* _ASTRING_ */ +#endif /* SIMPLEKERNEL_ASTRING */ diff --git a/src/libcxx/include/basic_string b/src/libcxx/include/basic_string index 7d00678e7..9ad92cfad 100644 --- a/src/libcxx/include/basic_string +++ b/src/libcxx/include/basic_string @@ -1,1956 +1,2059 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// basic_string for Simple-XX/SimpleKernel. - -#ifndef _BASIC_STRING_ -#define _BASIC_STRING_ +/** + * @file basic_string + * @brief stl basic_string 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_BASIC_STRING +#define SIMPLEKERNEL_BASIC_STRING // 这个头文件包含一个模板类 basic_string // 用于表示字符串类型 +#include "cstring" +#include "exceptdef" +#include "functional" #include "iostream" #include "iterator" #include "memory" -#include "functional" -#include "exceptdef" -#include "cstring" namespace mystl { - // char_traits +// char_traits - template - struct char_traits { - typedef CharType char_type; +template +struct char_traits { + typedef CharType char_type; - static size_t length(const char_type *str) { - size_t len = 0; - for (; *str != char_type(0); ++str) - ++len; - return len; + static size_t length(const char_type* str) { + size_t len = 0; + for (; *str != char_type(0); ++str) { + ++len; } + return len; + } - static int compare(const char_type *s1, const char_type *s2, size_t n) { - for (; n != 0; --n, ++s1, ++s2) { - if (*s1 < *s2) - return -1; - if (*s2 < *s1) - return 1; + static int compare(const char_type* s1, const char_type* s2, size_t n) { + for (; n != 0; --n, ++s1, ++s2) { + if (*s1 < *s2) { + return -1; + } + if (*s2 < *s1) { + return 1; } - return 0; } + return 0; + } - static char_type *copy(char_type *dst, const char_type *src, size_t n) { - MYSTL_DEBUG(src + n <= dst || dst + n <= src); - char_type *r = dst; - for (; n != 0; --n, ++dst, ++src) - *dst = *src; - return r; + static char_type* copy(char_type* dst, const char_type* src, size_t n) { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + char_type* r = dst; + for (; n != 0; --n, ++dst, ++src) { + *dst = *src; } + return r; + } - static char_type *move(char_type *dst, const char_type *src, size_t n) { - char_type *r = dst; - if (dst < src) { - for (; n != 0; --n, ++dst, ++src) - *dst = *src; + static char_type* move(char_type* dst, const char_type* src, size_t n) { + char_type* r = dst; + if (dst < src) { + for (; n != 0; --n, ++dst, ++src) { + *dst = *src; } - else if (src < dst) { - dst += n; - src += n; - for (; n != 0; --n) - *--dst = *--src; + } + else if (src < dst) { + dst += n; + src += n; + for (; n != 0; --n) { + *--dst = *--src; } - return r; } + return r; + } - static char_type *fill(char_type *dst, char_type ch, size_t count) { - char_type *r = dst; - for (; count > 0; --count, ++dst) - *dst = ch; - return r; + static char_type* fill(char_type* dst, char_type ch, size_t count) { + char_type* r = dst; + for (; count > 0; --count, ++dst) { + *dst = ch; } - }; + return r; + } +}; - // Partialized. char_traits - template <> - struct char_traits { - typedef char char_type; +// Partialized. char_traits +template <> +struct char_traits { + typedef char char_type; - static size_t length(const char_type *str) noexcept { - return std::strlen(str); - } + static size_t length(const char_type* str) noexcept { + return std::strlen(str); + } - static int compare(const char_type *s1, const char_type *s2, - size_t n) noexcept { - return std::memcmp(s1, s2, n); - } + static int + compare(const char_type* s1, const char_type* s2, size_t n) noexcept { + return std::memcmp(s1, s2, n); + } - static char_type *copy(char_type *dst, const char_type *src, - size_t n) noexcept { - MYSTL_DEBUG(src + n <= dst || dst + n <= src); - return static_cast(std::memcpy(dst, src, n)); - } + static char_type* + copy(char_type* dst, const char_type* src, size_t n) noexcept { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + return static_cast(std::memcpy(dst, src, n)); + } - static char_type *move(char_type *dst, const char_type *src, - size_t n) noexcept { - return static_cast(std::memmove(dst, src, n)); - } + static char_type* + move(char_type* dst, const char_type* src, size_t n) noexcept { + return static_cast(std::memmove(dst, src, n)); + } - static char_type *fill(char_type *dst, char_type ch, - size_t count) noexcept { - return static_cast(std::memset(dst, ch, count)); - } - }; - - // Partialized. char_traits - // template <> - // struct char_traits { - // typedef wchar_t char_type; - - // static size_t length(const char_type *str) noexcept { - // return std::wcslen(str); - // } - - // static int compare(const char_type *s1, const char_type *s2, - // size_t n) noexcept { - // return std::wmemcmp(s1, s2, n); - // } - - // static char_type *copy(char_type *dst, const char_type *src, - // size_t n) noexcept { - // MYSTL_DEBUG(src + n <= dst || dst + n <= src); - // return static_cast(std::wmemcpy(dst, src, n)); - // } - - // static char_type *move(char_type *dst, const char_type *src, - // size_t n) noexcept { - // return static_cast(std::wmemmove(dst, src, n)); - // } - - // static char_type *fill(char_type *dst, char_type ch, - // size_t count) noexcept { - // return static_cast(std::wmemset(dst, ch, count)); - // } - // }; - - // Partialized. char_traits - template <> - struct char_traits { - typedef char16_t char_type; - - static size_t length(const char_type *str) noexcept { - size_t len = 0; - for (; *str != char_type(0); ++str) - ++len; - return len; - } + static char_type* + fill(char_type* dst, char_type ch, size_t count) noexcept { + return static_cast(std::memset(dst, ch, count)); + } +}; - static int compare(const char_type *s1, const char_type *s2, - size_t n) noexcept { - for (; n != 0; --n, ++s1, ++s2) { - if (*s1 < *s2) - return -1; - if (*s2 < *s1) - return 1; +// Partialized. char_traits +// template <> +// struct char_traits { +// typedef wchar_t char_type; + +// static size_t length(const char_type *str) noexcept { +// return std::wcslen(str); +// } + +// static int compare(const char_type *s1, const char_type *s2, +// size_t n) noexcept { +// return std::wmemcmp(s1, s2, n); +// } + +// static char_type *copy(char_type *dst, const char_type *src, +// size_t n) noexcept { +// MYSTL_DEBUG(src + n <= dst || dst + n <= src); +// return static_cast(std::wmemcpy(dst, src, n)); +// } + +// static char_type *move(char_type *dst, const char_type *src, +// size_t n) noexcept { +// return static_cast(std::wmemmove(dst, src, n)); +// } + +// static char_type *fill(char_type *dst, char_type ch, +// size_t count) noexcept { +// return static_cast(std::wmemset(dst, ch, count)); +// } +// }; + +// Partialized. char_traits +template <> +struct char_traits { + typedef char16_t char_type; + + static size_t length(const char_type* str) noexcept { + size_t len = 0; + for (; *str != char_type(0); ++str) { + ++len; + } + return len; + } + + static int + compare(const char_type* s1, const char_type* s2, size_t n) noexcept { + for (; n != 0; --n, ++s1, ++s2) { + if (*s1 < *s2) { + return -1; + } + if (*s2 < *s1) { + return 1; } - return 0; } + return 0; + } - static char_type *copy(char_type *dst, const char_type *src, - size_t n) noexcept { - MYSTL_DEBUG(src + n <= dst || dst + n <= src); - char_type *r = dst; - for (; n != 0; --n, ++dst, ++src) - *dst = *src; - return r; + static char_type* + copy(char_type* dst, const char_type* src, size_t n) noexcept { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + char_type* r = dst; + for (; n != 0; --n, ++dst, ++src) { + *dst = *src; } + return r; + } - static char_type *move(char_type *dst, const char_type *src, - size_t n) noexcept { - char_type *r = dst; - if (dst < src) { - for (; n != 0; --n, ++dst, ++src) - *dst = *src; + static char_type* + move(char_type* dst, const char_type* src, size_t n) noexcept { + char_type* r = dst; + if (dst < src) { + for (; n != 0; --n, ++dst, ++src) { + *dst = *src; } - else if (src < dst) { - dst += n; - src += n; - for (; n != 0; --n) - *--dst = *--src; + } + else if (src < dst) { + dst += n; + src += n; + for (; n != 0; --n) { + *--dst = *--src; } - return r; } + return r; + } - static char_type *fill(char_type *dst, char_type ch, - size_t count) noexcept { - char_type *r = dst; - for (; count > 0; --count, ++dst) - *dst = ch; - return r; + static char_type* + fill(char_type* dst, char_type ch, size_t count) noexcept { + char_type* r = dst; + for (; count > 0; --count, ++dst) { + *dst = ch; } - }; - - // Partialized. char_traits - template <> - struct char_traits { - typedef char32_t char_type; - - static size_t length(const char_type *str) noexcept { - size_t len = 0; - for (; *str != char_type(0); ++str) - ++len; - return len; + return r; + } +}; + +// Partialized. char_traits +template <> +struct char_traits { + typedef char32_t char_type; + + static size_t length(const char_type* str) noexcept { + size_t len = 0; + for (; *str != char_type(0); ++str) { + ++len; } + return len; + } - static int compare(const char_type *s1, const char_type *s2, - size_t n) noexcept { - for (; n != 0; --n, ++s1, ++s2) { - if (*s1 < *s2) - return -1; - if (*s2 < *s1) - return 1; + static int + compare(const char_type* s1, const char_type* s2, size_t n) noexcept { + for (; n != 0; --n, ++s1, ++s2) { + if (*s1 < *s2) { + return -1; + } + if (*s2 < *s1) { + return 1; } - return 0; } + return 0; + } - static char_type *copy(char_type *dst, const char_type *src, - size_t n) noexcept { - MYSTL_DEBUG(src + n <= dst || dst + n <= src); - char_type *r = dst; - for (; n != 0; --n, ++dst, ++src) - *dst = *src; - return r; + static char_type* + copy(char_type* dst, const char_type* src, size_t n) noexcept { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + char_type* r = dst; + for (; n != 0; --n, ++dst, ++src) { + *dst = *src; } + return r; + } - static char_type *move(char_type *dst, const char_type *src, - size_t n) noexcept { - char_type *r = dst; - if (dst < src) { - for (; n != 0; --n, ++dst, ++src) - *dst = *src; + static char_type* + move(char_type* dst, const char_type* src, size_t n) noexcept { + char_type* r = dst; + if (dst < src) { + for (; n != 0; --n, ++dst, ++src) { + *dst = *src; } - else if (src < dst) { - dst += n; - src += n; - for (; n != 0; --n) - *--dst = *--src; + } + else if (src < dst) { + dst += n; + src += n; + for (; n != 0; --n) { + *--dst = *--src; } - return r; } + return r; + } - static char_type *fill(char_type *dst, char_type ch, - size_t count) noexcept { - char_type *r = dst; - for (; count > 0; --count, ++dst) - *dst = ch; - return r; + static char_type* + fill(char_type* dst, char_type ch, size_t count) noexcept { + char_type* r = dst; + for (; count > 0; --count, ++dst) { + *dst = ch; } - }; + return r; + } +}; // 初始化 basic_string 尝试分配的最小 buffer 大小,可能被忽略 #define STRING_INIT_SIZE 32 - // 模板类 basic_string - // 参数一代表字符类型,参数二代表萃取字符类型的方式,缺省使用 - // mystl::char_traits - template > - class basic_string { - public: - typedef CharTraits traits_type; - typedef CharTraits char_traits; - - typedef mystl::allocator allocator_type; - typedef mystl::allocator data_allocator; - - typedef typename allocator_type::value_type value_type; - typedef typename allocator_type::pointer pointer; - typedef typename allocator_type::const_pointer const_pointer; - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - typedef typename allocator_type::size_type size_type; - typedef typename allocator_type::difference_type difference_type; - - typedef value_type * iterator; - typedef const value_type * const_iterator; - typedef mystl::reverse_iterator reverse_iterator; - typedef mystl::reverse_iterator const_reverse_iterator; - - allocator_type get_allocator() { - return allocator_type(); - } +// 模板类 basic_string +// 参数一代表字符类型,参数二代表萃取字符类型的方式,缺省使用 +// mystl::char_traits +template > +class basic_string { +public: + typedef CharTraits traits_type; + typedef CharTraits char_traits; - static_assert(std::is_trivial::value, - "Character type of basic_string must be a POD"); - static_assert( - std::is_same::value, - "CharType must be same as traits_type::char_type"); + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; - public: - // 末尾位置的值,例: - // if (str.find('a') != string::npos) { /* do something */ } - static constexpr size_type npos = static_cast(-1); + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; - private: - iterator buffer_; // 储存字符串的起始位置 - size_type size_; // 大小 - size_type cap_; // 容量 + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; - public: - // 构造、复制、移动、析构函数 + allocator_type get_allocator() { + return allocator_type(); + } - basic_string() noexcept { - try_init(); - } + static_assert(std::is_trivial::value, + "Character type of basic_string must be a POD"); + static_assert( + std::is_same::value, + "CharType must be same as traits_type::char_type"); - basic_string(size_type n, value_type ch) - : buffer_(nullptr), size_(0), cap_(0) { - fill_init(n, ch); - } +public: + // 末尾位置的值,例: + // if (str.find('a') != string::npos) { /* do something */ } + static constexpr size_type npos = static_cast(-1); - basic_string(const basic_string &other, size_type pos) - : buffer_(nullptr), size_(0), cap_(0) { - init_from(other.buffer_, pos, other.size_ - pos); - } - basic_string(const basic_string &other, size_type pos, size_type count) - : buffer_(nullptr), size_(0), cap_(0) { - init_from(other.buffer_, pos, count); - } +private: + iterator buffer_; // 储存字符串的起始位置 + size_type size_; // 大小 + size_type cap_; // 容量 - basic_string(const_pointer str) : buffer_(nullptr), size_(0), cap_(0) { - init_from(str, 0, char_traits::length(str)); - } - basic_string(const_pointer str, size_type count) - : buffer_(nullptr), size_(0), cap_(0) { - init_from(str, 0, count); - } +public: + // 构造、复制、移动、析构函数 - template ::value, - int>::type = 0> - basic_string(Iter first, Iter last) { - copy_init(first, last, iterator_category(first)); - } - - basic_string(const basic_string &rhs) - : buffer_(nullptr), size_(0), cap_(0) { - init_from(rhs.buffer_, 0, rhs.size_); - } - basic_string(basic_string &&rhs) noexcept - : buffer_(rhs.buffer_), size_(rhs.size_), cap_(rhs.cap_) { - rhs.buffer_ = nullptr; - rhs.size_ = 0; - rhs.cap_ = 0; - } + basic_string() noexcept { + try_init(); + } - basic_string &operator=(const basic_string &rhs); - basic_string &operator=(basic_string &&rhs) noexcept; + basic_string(size_type n, value_type ch) + : buffer_(nullptr), size_(0), cap_(0) { + fill_init(n, ch); + } - basic_string &operator=(const_pointer str); - basic_string &operator=(value_type ch); + basic_string(const basic_string& other, size_type pos) + : buffer_(nullptr), size_(0), cap_(0) { + init_from(other.buffer_, pos, other.size_ - pos); + } - ~basic_string() { - destroy_buffer(); - } + basic_string(const basic_string& other, size_type pos, size_type count) + : buffer_(nullptr), size_(0), cap_(0) { + init_from(other.buffer_, pos, count); + } - public: - // 迭代器相关操作 - iterator begin() noexcept { - return buffer_; - } - const_iterator begin() const noexcept { - return buffer_; - } - iterator end() noexcept { - return buffer_ + size_; - } - const_iterator end() const noexcept { - return buffer_ + size_; - } + basic_string(const_pointer str) : buffer_(nullptr), size_(0), cap_(0) { + init_from(str, 0, char_traits::length(str)); + } - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } + basic_string(const_pointer str, size_type count) + : buffer_(nullptr), size_(0), cap_(0) { + init_from(str, 0, count); + } - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } + template ::value, int>::type + = 0> + basic_string(Iter first, Iter last) { + copy_init(first, last, iterator_category(first)); + } - // 容量相关操作 - bool empty() const noexcept { - return size_ == 0; - } + basic_string(const basic_string& rhs) + : buffer_(nullptr), size_(0), cap_(0) { + init_from(rhs.buffer_, 0, rhs.size_); + } - size_type size() const noexcept { - return size_; - } - size_type length() const noexcept { - return size_; - } - size_type capacity() const noexcept { - return cap_; - } - size_type max_size() const noexcept { - return static_cast(-1); - } + basic_string(basic_string&& rhs) noexcept + : buffer_(rhs.buffer_), size_(rhs.size_), cap_(rhs.cap_) { + rhs.buffer_ = nullptr; + rhs.size_ = 0; + rhs.cap_ = 0; + } - void reserve(size_type n); - void shrink_to_fit(); + basic_string& operator=(const basic_string& rhs); + basic_string& operator=(basic_string&& rhs) noexcept; - // 访问元素相关操作 - reference operator[](size_type n) { - MYSTL_DEBUG(n <= size_); - if (n == size_) - *(buffer_ + n) = value_type(); - return *(buffer_ + n); - } - const_reference operator[](size_type n) const { - MYSTL_DEBUG(n <= size_); - if (n == size_) - *(buffer_ + n) = value_type(); - return *(buffer_ + n); - } + basic_string& operator=(const_pointer str); + basic_string& operator=(value_type ch); - reference at(size_type n) { - THROW_OUT_OF_RANGE_IF(n >= size_, "basic_string::at()" - "subscript out of range"); - return (*this)[n]; - } - const_reference at(size_type n) const { - THROW_OUT_OF_RANGE_IF(n >= size_, "basic_string::at()" - "subscript out of range"); - return (*this)[n]; - } + ~basic_string() { + destroy_buffer(); + } - reference front() { - MYSTL_DEBUG(!empty()); - return *begin(); - } - const_reference front() const { - MYSTL_DEBUG(!empty()); - return *begin(); - } +public: + // 迭代器相关操作 + iterator begin() noexcept { + return buffer_; + } - reference back() { - MYSTL_DEBUG(!empty()); - return *(end() - 1); - } - const_reference back() const { - MYSTL_DEBUG(!empty()); - return *(end() - 1); - } + const_iterator begin() const noexcept { + return buffer_; + } - const_pointer data() const noexcept { - return to_raw_pointer(); - } - const_pointer c_str() const noexcept { - return to_raw_pointer(); - } + iterator end() noexcept { + return buffer_ + size_; + } - // 添加删除相关操作 + const_iterator end() const noexcept { + return buffer_ + size_; + } - // insert - iterator insert(const_iterator pos, value_type ch); - iterator insert(const_iterator pos, size_type count, value_type ch); + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } - template - iterator insert(const_iterator pos, Iter first, Iter last); + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } - // push_back / pop_back - void push_back(value_type ch) { - append(1, ch); - } - void pop_back() { - MYSTL_DEBUG(!empty()); - --size_; - } + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - // append - basic_string &append(size_type count, value_type ch); + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - basic_string &append(const basic_string &str) { - return append(str, 0, str.size_); - } - basic_string &append(const basic_string &str, size_type pos) { - return append(str, pos, str.size_ - pos); - } - basic_string &append(const basic_string &str, size_type pos, - size_type count); + const_iterator cbegin() const noexcept { + return begin(); + } - basic_string &append(const_pointer s) { - return append(s, char_traits::length(s)); - } - basic_string &append(const_pointer s, size_type count); + const_iterator cend() const noexcept { + return end(); + } - template ::value, - int>::type = 0> - basic_string &append(Iter first, Iter last) { - return append_range(first, last); - } + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } - // erase /clear - iterator erase(const_iterator pos); - iterator erase(const_iterator first, const_iterator last); + const_reverse_iterator crend() const noexcept { + return rend(); + } - // resize - void resize(size_type count) { - resize(count, value_type()); - } - void resize(size_type count, value_type ch); + // 容量相关操作 + bool empty() const noexcept { + return size_ == 0; + } - void clear() noexcept { - size_ = 0; - } + size_type size() const noexcept { + return size_; + } - // basic_string 相关操作 - - // compare - int compare(const basic_string &other) const; - int compare(size_type pos1, size_type count1, - const basic_string &other) const; - int compare(size_type pos1, size_type count1, const basic_string &other, - size_type pos2, size_type count2 = npos) const; - int compare(const_pointer s) const; - int compare(size_type pos1, size_type count1, const_pointer s) const; - int compare(size_type pos1, size_type count1, const_pointer s, - size_type count2) const; - - // substr - basic_string substr(size_type index, size_type count = npos) { - count = mystl::min(count, size_ - index); - return basic_string(buffer_ + index, buffer_ + index + count); - } + size_type length() const noexcept { + return size_; + } - // replace - basic_string &replace(size_type pos, size_type count, - const basic_string &str) { - THROW_OUT_OF_RANGE_IF( - pos > size_, - "basic_string::replace's pos out of range"); - return replace_cstr(buffer_ + pos, count, str.buffer_, str.size_); - } - basic_string &replace(const_iterator first, const_iterator last, - const basic_string &str) { - MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); - return replace_cstr(first, static_cast(last - first), - str.buffer_, str.size_); - } + size_type capacity() const noexcept { + return cap_; + } - basic_string &replace(size_type pos, size_type count, - const_pointer str) { - THROW_OUT_OF_RANGE_IF( - pos > size_, - "basic_string::replace's pos out of range"); - return replace_cstr(buffer_ + pos, count, str, - char_traits::length(str)); - } - basic_string &replace(const_iterator first, const_iterator last, - const_pointer str) { - MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); - return replace_cstr(first, static_cast(last - first), - str, char_traits::length(str)); - } + size_type max_size() const noexcept { + return static_cast(-1); + } - basic_string &replace(size_type pos, size_type count, const_pointer str, - size_type count2) { - THROW_OUT_OF_RANGE_IF( - pos > size_, - "basic_string::replace's pos out of range"); - return replace_cstr(buffer_ + pos, count, str, count2); - } - basic_string &replace(const_iterator first, const_iterator last, - const_pointer str, size_type count) { - MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); - return replace_cstr(first, static_cast(last - first), - str, count); - } + void reserve(size_type n); + void shrink_to_fit(); - basic_string &replace(size_type pos, size_type count, size_type count2, - value_type ch) { - THROW_OUT_OF_RANGE_IF( - pos > size_, - "basic_string::replace's pos out of range"); - return replace_fill(buffer_ + pos, count, count2, ch); - } - basic_string &replace(const_iterator first, const_iterator last, - size_type count, value_type ch) { - MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); - return replace_fill(first, static_cast(last - first), - count, ch); + // 访问元素相关操作 + reference operator[](size_type n) { + MYSTL_DEBUG(n <= size_); + if (n == size_) { + *(buffer_ + n) = value_type(); } + return *(buffer_ + n); + } - basic_string &replace(size_type pos1, size_type count1, - const basic_string &str, size_type pos2, - size_type count2 = npos) { - THROW_OUT_OF_RANGE_IF( - pos1 > size_ || pos2 > str.size_, - "basic_string::replace's pos out of range"); - return replace_cstr(buffer_ + pos1, count1, str.buffer_ + pos2, - count2); + const_reference operator[](size_type n) const { + MYSTL_DEBUG(n <= size_); + if (n == size_) { + *(buffer_ + n) = value_type(); } + return *(buffer_ + n); + } - template ::value, - int>::type = 0> - basic_string &replace(const_iterator first, const_iterator last, - Iter first2, Iter last2) { - MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); - return replace_copy(first, last, first2, last2); - } + reference at(size_type n) { + THROW_OUT_OF_RANGE_IF(n >= size_, "basic_string::at()" + "subscript out of range"); + return (*this)[n]; + } - // reverse - void reverse() noexcept; - - // swap - void swap(basic_string &rhs) noexcept; - - // 查找相关操作 - - // find - size_type find(value_type ch, size_type pos = 0) const noexcept; - size_type find(const_pointer str, size_type pos = 0) const noexcept; - size_type find(const_pointer str, size_type pos, - size_type count) const noexcept; - size_type find(const basic_string &str, - size_type pos = 0) const noexcept; - - // rfind - size_type rfind(value_type ch, size_type pos = npos) const noexcept; - size_type rfind(const_pointer str, size_type pos = npos) const noexcept; - size_type rfind(const_pointer str, size_type pos, - size_type count) const noexcept; - size_type rfind(const basic_string &str, - size_type pos = npos) const noexcept; - - // find_first_of - size_type find_first_of(value_type ch, - size_type pos = 0) const noexcept; - size_type find_first_of(const_pointer s, - size_type pos = 0) const noexcept; - size_type find_first_of(const_pointer s, size_type pos, - size_type count) const noexcept; - size_type find_first_of(const basic_string &str, - size_type pos = 0) const noexcept; + const_reference at(size_type n) const { + THROW_OUT_OF_RANGE_IF(n >= size_, "basic_string::at()" + "subscript out of range"); + return (*this)[n]; + } - // find_first_not_of - size_type find_first_not_of(value_type ch, - size_type pos = 0) const noexcept; - size_type find_first_not_of(const_pointer s, - size_type pos = 0) const noexcept; - size_type find_first_not_of(const_pointer s, size_type pos, - size_type count) const noexcept; - size_type find_first_not_of(const basic_string &str, - size_type pos = 0) const noexcept; - - // find_last_of - size_type find_last_of(value_type ch, size_type pos = 0) const noexcept; - size_type find_last_of(const_pointer s, - size_type pos = 0) const noexcept; - size_type find_last_of(const_pointer s, size_type pos, - size_type count) const noexcept; - size_type find_last_of(const basic_string &str, - size_type pos = 0) const noexcept; - - // find_last_not_of - size_type find_last_not_of(value_type ch, - size_type pos = 0) const noexcept; - size_type find_last_not_of(const_pointer s, - size_type pos = 0) const noexcept; - size_type find_last_not_of(const_pointer s, size_type pos, - size_type count) const noexcept; - size_type find_last_not_of(const basic_string &str, - size_type pos = 0) const noexcept; - - // count - size_type count(value_type ch, size_type pos = 0) const noexcept; - - public: - // 重载 operator+= - basic_string &operator+=(const basic_string &str) { - return append(str); - } - basic_string &operator+=(value_type ch) { - return append(1, ch); - } - basic_string &operator+=(const_pointer str) { - return append(str, str + char_traits::length(str)); - } + reference front() { + MYSTL_DEBUG(!empty()); + return *begin(); + } - // 重载 operator >> / operatror << - - // friend std::istream &operator>>(std::istream &is, basic_string &str) - // { - // value_type *buf = new value_type[4096]; - // is >> buf; - // basic_string tmp(buf); - // str = std::move(tmp); - // delete[] buf; - // return is; - // } - - friend std::ostream &operator<<(std::ostream & os, - const basic_string &str) { - for (size_type i = 0; i < str.size_; ++i) - os << *(str.buffer_ + i); - return os; - } + const_reference front() const { + MYSTL_DEBUG(!empty()); + return *begin(); + } - private: - // helper functions + reference back() { + MYSTL_DEBUG(!empty()); + return *(end() - 1); + } - // init / destroy - void try_init() noexcept; + const_reference back() const { + MYSTL_DEBUG(!empty()); + return *(end() - 1); + } - void fill_init(size_type n, value_type ch); + const_pointer data() const noexcept { + return to_raw_pointer(); + } - template - void copy_init(Iter first, Iter last, mystl::input_iterator_tag); - template - void copy_init(Iter first, Iter last, mystl::forward_iterator_tag); + const_pointer c_str() const noexcept { + return to_raw_pointer(); + } - void init_from(const_pointer src, size_type pos, size_type n); + // 添加删除相关操作 - void destroy_buffer(); + // insert + iterator insert(const_iterator pos, value_type ch); + iterator insert(const_iterator pos, size_type count, value_type ch); - // get raw pointer - const_pointer to_raw_pointer() const; + template + iterator insert(const_iterator pos, Iter first, Iter last); - // shrink_to_fit - void reinsert(size_type size); + // push_back / pop_back + void push_back(value_type ch) { + append(1, ch); + } - // append - template - basic_string &append_range(Iter first, Iter last); + void pop_back() { + MYSTL_DEBUG(!empty()); + --size_; + } - // compare - int compare_cstr(const_pointer s1, size_type n1, const_pointer s2, - size_type n2) const; + // append + basic_string& append(size_type count, value_type ch); - // replace - basic_string &replace_cstr(const_iterator first, size_type count1, - const_pointer str, size_type count2); - basic_string &replace_fill(const_iterator first, size_type count1, - size_type count2, value_type ch); - template - basic_string &replace_copy(const_iterator first, const_iterator last, - Iter first2, Iter last2); + basic_string& append(const basic_string& str) { + return append(str, 0, str.size_); + } - // reallocate - void reallocate(size_type need); - iterator reallocate_and_fill(iterator pos, size_type n, value_type ch); - iterator reallocate_and_copy(iterator pos, const_iterator first, - const_iterator last); - }; + basic_string& append(const basic_string& str, size_type pos) { + return append(str, pos, str.size_ - pos); + } - /*****************************************************************************************/ + basic_string& + append(const basic_string& str, size_type pos, size_type count); - // 复制赋值操作符 - template - basic_string & - basic_string::operator=(const basic_string &rhs) { - if (this != &rhs) { - basic_string tmp(rhs); - swap(tmp); - } - return *this; + basic_string& append(const_pointer s) { + return append(s, char_traits::length(s)); } - // 移动赋值操作符 - template - basic_string & - basic_string::operator=(basic_string &&rhs) noexcept { - destroy_buffer(); - buffer_ = rhs.buffer_; - size_ = rhs.size_; - cap_ = rhs.cap_; - rhs.buffer_ = nullptr; - rhs.size_ = 0; - rhs.cap_ = 0; - return *this; - } + basic_string& append(const_pointer s, size_type count); - // 用一个字符串赋值 - template - basic_string & - basic_string::operator=(const_pointer str) { - const size_type len = char_traits::length(str); - if (cap_ < len) { - auto new_buffer = data_allocator::allocate(len + 1); - data_allocator::deallocate(buffer_); - buffer_ = new_buffer; - cap_ = len + 1; - } - char_traits::copy(buffer_, str, len); - size_ = len; - return *this; + template ::value, int>::type + = 0> + basic_string& append(Iter first, Iter last) { + return append_range(first, last); } - // 用一个字符赋值 - template - basic_string & - basic_string::operator=(value_type ch) { - if (cap_ < 1) { - auto new_buffer = data_allocator::allocate(2); - data_allocator::deallocate(buffer_); - buffer_ = new_buffer; - cap_ = 2; - } - *buffer_ = ch; - size_ = 1; - return *this; + // erase /clear + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + + // resize + void resize(size_type count) { + resize(count, value_type()); } - // 预留储存空间 - template - void basic_string::reserve(size_type n) { - if (cap_ < n) { - THROW_LENGTH_ERROR_IF(n > max_size(), - "n can not larger than max_size()" - "in basic_string::reserve(n)"); - auto new_buffer = data_allocator::allocate(n); - char_traits::move(new_buffer, buffer_, size_); - buffer_ = new_buffer; - cap_ = n; - } + void resize(size_type count, value_type ch); + + void clear() noexcept { + size_ = 0; } - // 减少不用的空间 - template - void basic_string::shrink_to_fit() { - if (size_ != cap_) { - reinsert(size_); - } + // basic_string 相关操作 + + // compare + int compare(const basic_string& other) const; + int + compare(size_type pos1, size_type count1, const basic_string& other) const; + int compare(size_type pos1, size_type count1, const basic_string& other, + size_type pos2, size_type count2 = npos) const; + int compare(const_pointer s) const; + int compare(size_type pos1, size_type count1, const_pointer s) const; + int compare(size_type pos1, size_type count1, const_pointer s, + size_type count2) const; + + // substr + basic_string substr(size_type index, size_type count = npos) { + count = mystl::min(count, size_ - index); + return basic_string(buffer_ + index, buffer_ + index + count); } - // 在 pos 处插入一个元素 - template - typename basic_string::iterator - basic_string::insert(const_iterator pos, - value_type ch) { - iterator r = const_cast(pos); - if (size_ == cap_) { - return reallocate_and_fill(r, 1, ch); - } - char_traits::move(r + 1, r, end() - r); - ++size_; - *r = ch; - return r; + // replace + basic_string& + replace(size_type pos, size_type count, const basic_string& str) { + THROW_OUT_OF_RANGE_IF( + pos > size_, + "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos, count, str.buffer_, str.size_); } - // 在 pos 处插入 n 个元素 - template - typename basic_string::iterator - basic_string::insert(const_iterator pos, - size_type count, value_type ch) { - iterator r = const_cast(pos); - if (count == 0) - return r; - if (cap_ - size_ < count) { - return reallocate_and_fill(r, count, ch); - } - if (pos == end()) { - char_traits::fill(end(), ch, count); - size_ += count; - return r; - } - char_traits::move(r + count, r, count); - char_traits::fill(r, ch, count); - size_ += count; - return r; + basic_string& replace(const_iterator first, const_iterator last, + const basic_string& str) { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_cstr(first, static_cast(last - first), + str.buffer_, str.size_); } - // 在 pos 处插入 [first, last) 内的元素 - template - template - typename basic_string::iterator - basic_string::insert(const_iterator pos, Iter first, - Iter last) { - iterator r = const_cast(pos); - const size_type len = mystl::distance(first, last); - if (len == 0) - return r; - if (cap_ - size_ < len) { - return reallocate_and_copy(r, first, last); - } - if (pos == end()) { - mystl::uninitialized_copy(first, last, end()); - size_ += len; - return r; - } - char_traits::move(r + len, r, len); - mystl::uninitialized_copy(first, last, r); - size_ += len; - return r; + basic_string& replace(size_type pos, size_type count, const_pointer str) { + THROW_OUT_OF_RANGE_IF( + pos > size_, + "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos, count, str, + char_traits::length(str)); } - // 在末尾添加 count 个 ch - template - basic_string & - basic_string::append(size_type count, value_type ch) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - count, - "basic_string's size too big"); - if (cap_ - size_ < count) { - reallocate(count); - } - char_traits::fill(buffer_ + size_, ch, count); - size_ += count; - return *this; + basic_string& + replace(const_iterator first, const_iterator last, const_pointer str) { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_cstr(first, static_cast(last - first), str, + char_traits::length(str)); } - // 在末尾添加 [str[pos] str[pos+count]) 一段 - template - basic_string & - basic_string::append(const basic_string &str, - size_type pos, size_type count) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - count, - "basic_string's size too big"); - if (count == 0) - return *this; - if (cap_ - size_ < count) { - reallocate(count); - } - char_traits::copy(buffer_ + size_, str.buffer_ + pos, count); - size_ += count; - return *this; + basic_string& replace(size_type pos, size_type count, const_pointer str, + size_type count2) { + THROW_OUT_OF_RANGE_IF( + pos > size_, + "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos, count, str, count2); } - // 在末尾添加 [s, s+count) 一段 - template - basic_string & - basic_string::append(const_pointer s, - size_type count) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - count, - "basic_string's size too big"); - if (cap_ - size_ < count) { - reallocate(count); - } - char_traits::copy(buffer_ + size_, s, count); - size_ += count; - return *this; + basic_string& replace(const_iterator first, const_iterator last, + const_pointer str, size_type count) { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_cstr(first, static_cast(last - first), str, + count); } - // 删除 pos 处的元素 - template - typename basic_string::iterator - basic_string::erase(const_iterator pos) { - MYSTL_DEBUG(pos != end()); - iterator r = const_cast(pos); - char_traits::move(r, pos + 1, end() - pos - 1); - --size_; - return r; + basic_string& + replace(size_type pos, size_type count, size_type count2, value_type ch) { + THROW_OUT_OF_RANGE_IF( + pos > size_, + "basic_string::replace's pos out of range"); + return replace_fill(buffer_ + pos, count, count2, ch); } - // 删除 [first, last) 的元素 - template - typename basic_string::iterator - basic_string::erase(const_iterator first, - const_iterator last) { - if (first == begin() && last == end()) { - clear(); - return end(); - } - const size_type n = end() - last; - iterator r = const_cast(first); - char_traits::move(r, last, n); - size_ -= (last - first); - return r; + basic_string& replace(const_iterator first, const_iterator last, + size_type count, value_type ch) { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_fill(first, static_cast(last - first), count, + ch); + } + + basic_string& + replace(size_type pos1, size_type count1, const basic_string& str, + size_type pos2, size_type count2 = npos) { + THROW_OUT_OF_RANGE_IF( + pos1 > size_ || pos2 > str.size_, + "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos1, count1, str.buffer_ + pos2, count2); + } + + template ::value, int>::type + = 0> + basic_string& replace(const_iterator first, const_iterator last, + Iter first2, Iter last2) { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_copy(first, last, first2, last2); + } + + // reverse + void reverse() noexcept; + + // swap + void swap(basic_string& rhs) noexcept; + + // 查找相关操作 + + // find + size_type find(value_type ch, size_type pos = 0) const noexcept; + size_type find(const_pointer str, size_type pos = 0) const noexcept; + size_type + find(const_pointer str, size_type pos, size_type count) const noexcept; + size_type find(const basic_string& str, size_type pos = 0) const noexcept; + + // rfind + size_type rfind(value_type ch, size_type pos = npos) const noexcept; + size_type rfind(const_pointer str, size_type pos = npos) const noexcept; + size_type + rfind(const_pointer str, size_type pos, size_type count) const noexcept; + size_type + rfind(const basic_string& str, size_type pos = npos) const noexcept; + + // find_first_of + size_type find_first_of(value_type ch, size_type pos = 0) const noexcept; + size_type find_first_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_first_of(const_pointer s, size_type pos, + size_type count) const noexcept; + size_type + find_first_of(const basic_string& str, size_type pos = 0) const noexcept; + + // find_first_not_of + size_type + find_first_not_of(value_type ch, size_type pos = 0) const noexcept; + size_type + find_first_not_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_first_not_of(const_pointer s, size_type pos, + size_type count) const noexcept; + size_type find_first_not_of(const basic_string& str, + size_type pos = 0) const noexcept; + + // find_last_of + size_type find_last_of(value_type ch, size_type pos = 0) const noexcept; + size_type find_last_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_last_of(const_pointer s, size_type pos, + size_type count) const noexcept; + size_type + find_last_of(const basic_string& str, size_type pos = 0) const noexcept; + + // find_last_not_of + size_type find_last_not_of(value_type ch, size_type pos = 0) const noexcept; + size_type + find_last_not_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_last_not_of(const_pointer s, size_type pos, + size_type count) const noexcept; + size_type + find_last_not_of(const basic_string& str, size_type pos = 0) const noexcept; + + // count + size_type count(value_type ch, size_type pos = 0) const noexcept; + +public: + // 重载 operator+= + basic_string& operator+=(const basic_string& str) { + return append(str); } - // 重置容器大小 - template - void basic_string::resize(size_type count, - value_type ch) { - if (count < size_) { - erase(buffer_ + count, buffer_ + size_); - } - else { - append(count - size_, ch); - } + basic_string& operator+=(value_type ch) { + return append(1, ch); } - // 比较两个 basic_string,小于返回 -1,大于返回 1,等于返回 0 - template - int basic_string::compare( - const basic_string &other) const { - return compare_cstr(buffer_, size_, other.buffer_, other.size_); - } - - // 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 比较 - template - int basic_string::compare( - size_type pos1, size_type count1, const basic_string &other) const { - auto n1 = mystl::min(count1, size_ - pos1); - return compare_cstr(buffer_ + pos1, n1, other.buffer_, other.size_); - } - - // 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 下标 pos2 开始的 - // count2 个字符比较 - template - int basic_string::compare(size_type pos1, - size_type count1, - const basic_string &other, - size_type pos2, - size_type count2) const { - auto n1 = mystl::min(count1, size_ - pos1); - auto n2 = mystl::min(count2, other.size_ - pos2); - return compare_cstr(buffer_, n1, other.buffer_, n2); - } - - // 跟一个字符串比较 - template - int basic_string::compare(const_pointer s) const { - auto n2 = char_traits::length(s); - return compare_cstr(buffer_, size_, s, n2); - } - - // 从下标 pos1 开始的 count1 个字符跟另一个字符串比较 - template - int basic_string::compare(size_type pos1, - size_type count1, - const_pointer s) const { - auto n1 = mystl::min(count1, size_ - pos1); - auto n2 = char_traits::length(s); - return compare_cstr(buffer_, n1, s, n2); - } - - // 从下标 pos1 开始的 count1 个字符跟另一个字符串的前 count2 个字符比较 - template - int basic_string::compare(size_type pos1, - size_type count1, - const_pointer s, - size_type count2) const { - auto n1 = mystl::min(count1, size_ - pos1); - return compare_cstr(buffer_, n1, s, count2); - } - - // 反转 basic_string - template - void basic_string::reverse() noexcept { - for (auto i = begin(), j = end(); i < j;) { - mystl::iter_swap(i++, --j); - } + basic_string& operator+=(const_pointer str) { + return append(str, str + char_traits::length(str)); } - // 交换两个 basic_string - template - void basic_string::swap(basic_string &rhs) noexcept { - if (this != &rhs) { - mystl::swap(buffer_, rhs.buffer_); - mystl::swap(size_, rhs.size_); - mystl::swap(cap_, rhs.cap_); + // 重载 operator >> / operatror << + + // friend std::istream &operator>>(std::istream &is, basic_string &str) + // { + // value_type *buf = new value_type[4096]; + // is >> buf; + // basic_string tmp(buf); + // str = std::move(tmp); + // delete[] buf; + // return is; + // } + + friend std::ostream& operator<<(std::ostream& os, const basic_string& str) { + for (size_type i = 0; i < str.size_; ++i) { + os << *(str.buffer_ + i); } + return os; } - // 从下标 pos 开始查找字符为 ch 的元素,若找到返回其下标,否则返回 npos - template - typename basic_string::size_type - basic_string::find(value_type ch, - size_type pos) const noexcept { - for (auto i = pos; i < size_; ++i) { - if (*(buffer_ + i) == ch) - return i; - } +private: + // helper functions + + // init / destroy + void try_init() noexcept; + + void fill_init(size_type n, value_type ch); + + template + void copy_init(Iter first, Iter last, mystl::input_iterator_tag); + template + void copy_init(Iter first, Iter last, mystl::forward_iterator_tag); + + void init_from(const_pointer src, size_type pos, size_type n); + + void destroy_buffer(); + + // get raw pointer + const_pointer to_raw_pointer() const; + + // shrink_to_fit + void reinsert(size_type size); + + // append + template + basic_string& append_range(Iter first, Iter last); + + // compare + int compare_cstr(const_pointer s1, size_type n1, const_pointer s2, + size_type n2) const; + + // replace + basic_string& replace_cstr(const_iterator first, size_type count1, + const_pointer str, size_type count2); + basic_string& replace_fill(const_iterator first, size_type count1, + size_type count2, value_type ch); + template + basic_string& replace_copy(const_iterator first, const_iterator last, + Iter first2, Iter last2); + + // reallocate + void reallocate(size_type need); + iterator reallocate_and_fill(iterator pos, size_type n, value_type ch); + iterator reallocate_and_copy(iterator pos, const_iterator first, + const_iterator last); +}; + +/*****************************************************************************************/ + +// 复制赋值操作符 +template +basic_string& +basic_string::operator=(const basic_string& rhs) { + if (this != &rhs) { + basic_string tmp(rhs); + swap(tmp); + } + return *this; +} + +// 移动赋值操作符 +template +basic_string& +basic_string::operator=(basic_string&& rhs) noexcept { + destroy_buffer(); + buffer_ = rhs.buffer_; + size_ = rhs.size_; + cap_ = rhs.cap_; + rhs.buffer_ = nullptr; + rhs.size_ = 0; + rhs.cap_ = 0; + return *this; +} + +// 用一个字符串赋值 +template +basic_string& +basic_string::operator=(const_pointer str) { + const size_type len = char_traits::length(str); + if (cap_ < len) { + auto new_buffer = data_allocator::allocate(len + 1); + data_allocator::deallocate(buffer_); + buffer_ = new_buffer; + cap_ = len + 1; + } + char_traits::copy(buffer_, str, len); + size_ = len; + return *this; +} + +// 用一个字符赋值 +template +basic_string& +basic_string::operator=(value_type ch) { + if (cap_ < 1) { + auto new_buffer = data_allocator::allocate(2); + data_allocator::deallocate(buffer_); + buffer_ = new_buffer; + cap_ = 2; + } + *buffer_ = ch; + size_ = 1; + return *this; +} + +// 预留储存空间 +template +void basic_string::reserve(size_type n) { + if (cap_ < n) { + THROW_LENGTH_ERROR_IF(n > max_size(), + "n can not larger than max_size()" + "in basic_string::reserve(n)"); + auto new_buffer = data_allocator::allocate(n); + char_traits::move(new_buffer, buffer_, size_); + buffer_ = new_buffer; + cap_ = n; + } +} + +// 减少不用的空间 +template +void basic_string::shrink_to_fit() { + if (size_ != cap_) { + reinsert(size_); + } +} + +// 在 pos 处插入一个元素 +template +typename basic_string::iterator +basic_string::insert(const_iterator pos, value_type ch) { + iterator r = const_cast(pos); + if (size_ == cap_) { + return reallocate_and_fill(r, 1, ch); + } + char_traits::move(r + 1, r, end() - r); + ++size_; + *r = ch; + return r; +} + +// 在 pos 处插入 n 个元素 +template +typename basic_string::iterator +basic_string::insert(const_iterator pos, size_type count, + value_type ch) { + iterator r = const_cast(pos); + if (count == 0) { + return r; + } + if (cap_ - size_ < count) { + return reallocate_and_fill(r, count, ch); + } + if (pos == end()) { + char_traits::fill(end(), ch, count); + size_ += count; + return r; + } + char_traits::move(r + count, r, count); + char_traits::fill(r, ch, count); + size_ += count; + return r; +} + +// 在 pos 处插入 [first, last) 内的元素 +template +template +typename basic_string::iterator +basic_string::insert(const_iterator pos, Iter first, + Iter last) { + iterator r = const_cast(pos); + const size_type len = mystl::distance(first, last); + if (len == 0) { + return r; + } + if (cap_ - size_ < len) { + return reallocate_and_copy(r, first, last); + } + if (pos == end()) { + mystl::uninitialized_copy(first, last, end()); + size_ += len; + return r; + } + char_traits::move(r + len, r, len); + mystl::uninitialized_copy(first, last, r); + size_ += len; + return r; +} + +// 在末尾添加 count 个 ch +template +basic_string& +basic_string::append(size_type count, value_type ch) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - count, + "basic_string's size too big"); + if (cap_ - size_ < count) { + reallocate(count); + } + char_traits::fill(buffer_ + size_, ch, count); + size_ += count; + return *this; +} + +// 在末尾添加 [str[pos] str[pos+count]) 一段 +template +basic_string& +basic_string::append(const basic_string& str, + size_type pos, size_type count) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - count, + "basic_string's size too big"); + if (count == 0) { + return *this; + } + if (cap_ - size_ < count) { + reallocate(count); + } + char_traits::copy(buffer_ + size_, str.buffer_ + pos, count); + size_ += count; + return *this; +} + +// 在末尾添加 [s, s+count) 一段 +template +basic_string& +basic_string::append(const_pointer s, size_type count) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - count, + "basic_string's size too big"); + if (cap_ - size_ < count) { + reallocate(count); + } + char_traits::copy(buffer_ + size_, s, count); + size_ += count; + return *this; +} + +// 删除 pos 处的元素 +template +typename basic_string::iterator +basic_string::erase(const_iterator pos) { + MYSTL_DEBUG(pos != end()); + iterator r = const_cast(pos); + char_traits::move(r, pos + 1, end() - pos - 1); + --size_; + return r; +} + +// 删除 [first, last) 的元素 +template +typename basic_string::iterator +basic_string::erase(const_iterator first, + const_iterator last) { + if (first == begin() && last == end()) { + clear(); + return end(); + } + const size_type n = end() - last; + iterator r = const_cast(first); + char_traits::move(r, last, n); + size_ -= (last - first); + return r; +} + +// 重置容器大小 +template +void basic_string::resize(size_type count, + value_type ch) { + if (count < size_) { + erase(buffer_ + count, buffer_ + size_); + } + else { + append(count - size_, ch); + } +} + +// 比较两个 basic_string,小于返回 -1,大于返回 1,等于返回 0 +template +int basic_string::compare( + const basic_string& other) const { + return compare_cstr(buffer_, size_, other.buffer_, other.size_); +} + +// 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 比较 +template +int basic_string::compare( + size_type pos1, size_type count1, const basic_string& other) const { + auto n1 = mystl::min(count1, size_ - pos1); + return compare_cstr(buffer_ + pos1, n1, other.buffer_, other.size_); +} + +// 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 下标 pos2 开始的 +// count2 个字符比较 +template +int basic_string::compare(size_type pos1, + size_type count1, + const basic_string& other, + size_type pos2, + size_type count2) const { + auto n1 = mystl::min(count1, size_ - pos1); + auto n2 = mystl::min(count2, other.size_ - pos2); + return compare_cstr(buffer_, n1, other.buffer_, n2); +} + +// 跟一个字符串比较 +template +int basic_string::compare(const_pointer s) const { + auto n2 = char_traits::length(s); + return compare_cstr(buffer_, size_, s, n2); +} + +// 从下标 pos1 开始的 count1 个字符跟另一个字符串比较 +template +int basic_string::compare(size_type pos1, + size_type count1, + const_pointer s) const { + auto n1 = mystl::min(count1, size_ - pos1); + auto n2 = char_traits::length(s); + return compare_cstr(buffer_, n1, s, n2); +} + +// 从下标 pos1 开始的 count1 个字符跟另一个字符串的前 count2 个字符比较 +template +int basic_string::compare(size_type pos1, + size_type count1, + const_pointer s, + size_type count2) const { + auto n1 = mystl::min(count1, size_ - pos1); + return compare_cstr(buffer_, n1, s, count2); +} + +// 反转 basic_string +template +void basic_string::reverse() noexcept { + for (auto i = begin(), j = end(); i < j;) { + mystl::iter_swap(i++, --j); + } +} + +// 交换两个 basic_string +template +void basic_string::swap(basic_string& rhs) noexcept { + if (this != &rhs) { + mystl::swap(buffer_, rhs.buffer_); + mystl::swap(size_, rhs.size_); + mystl::swap(cap_, rhs.cap_); + } +} + +// 从下标 pos 开始查找字符为 ch 的元素,若找到返回其下标,否则返回 npos +template +typename basic_string::size_type +basic_string::find(value_type ch, + size_type pos) const noexcept { + for (auto i = pos; i < size_; ++i) { + if (*(buffer_ + i) == ch) { + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找字符串 str,若找到返回起始位置的下标,否则返回 npos +template +typename basic_string::size_type +basic_string::find(const_pointer str, + size_type pos) const noexcept { + const auto len = char_traits::length(str); + if (len == 0) { + return pos; + } + if (size_ - pos < len) { return npos; } - - // 从下标 pos 开始查找字符串 str,若找到返回起始位置的下标,否则返回 npos - template - typename basic_string::size_type - basic_string::find(const_pointer str, - size_type pos) const noexcept { - const auto len = char_traits::length(str); - if (len == 0) - return pos; - if (size_ - pos < len) - return npos; - const auto left = size_ - len; - for (auto i = pos; i <= left; ++i) { - if (*(buffer_ + i) == *str) { - size_type j = 1; - for (; j < len; ++j) { - if (*(buffer_ + i + j) != *(str + j)) - break; + const auto left = size_ - len; + for (auto i = pos; i <= left; ++i) { + if (*(buffer_ + i) == *str) { + size_type j = 1; + for (; j < len; ++j) { + if (*(buffer_ + i + j) != *(str + j)) { + break; } - if (j == len) - return i; + } + if (j == len) { + return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找字符串 str 的前 count - // 个字符,若找到返回起始位置的下标,否则返回 npos - template - typename basic_string::size_type - basic_string::find(const_pointer str, size_type pos, - size_type count) const noexcept { - if (count == 0) - return pos; - if (size_ - pos < count) - return npos; - const auto left = size_ - count; - for (auto i = pos; i <= left; ++i) { - if (*(buffer_ + i) == *str) { - size_type j = 1; - for (; j < count; ++j) { - if (*(buffer_ + i + j) != *(str + j)) - break; +// 从下标 pos 开始查找字符串 str 的前 count +// 个字符,若找到返回起始位置的下标,否则返回 npos +template +typename basic_string::size_type +basic_string::find(const_pointer str, size_type pos, + size_type count) const noexcept { + if (count == 0) { + return pos; + } + if (size_ - pos < count) { + return npos; + } + const auto left = size_ - count; + for (auto i = pos; i <= left; ++i) { + if (*(buffer_ + i) == *str) { + size_type j = 1; + for (; j < count; ++j) { + if (*(buffer_ + i + j) != *(str + j)) { + break; } - if (j == count) - return i; + } + if (j == count) { + return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找字符串 str,若找到返回起始位置的下标,否则返回 npos - template - typename basic_string::size_type - basic_string::find(const basic_string &str, - size_type pos) const noexcept { - const size_type count = str.size_; - if (count == 0) - return pos; - if (size_ - pos < count) - return npos; - const auto left = size_ - count; - for (auto i = pos; i <= left; ++i) { - if (*(buffer_ + i) == str.front()) { - size_type j = 1; - for (; j < count; ++j) { - if (*(buffer_ + i + j) != str[j]) - break; +// 从下标 pos 开始查找字符串 str,若找到返回起始位置的下标,否则返回 npos +template +typename basic_string::size_type +basic_string::find(const basic_string& str, + size_type pos) const noexcept { + const size_type count = str.size_; + if (count == 0) { + return pos; + } + if (size_ - pos < count) { + return npos; + } + const auto left = size_ - count; + for (auto i = pos; i <= left; ++i) { + if (*(buffer_ + i) == str.front()) { + size_type j = 1; + for (; j < count; ++j) { + if (*(buffer_ + i + j) != str[j]) { + break; } - if (j == count) - return i; + } + if (j == count) { + return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始反向查找值为 ch 的元素,与 find 类似 - template - typename basic_string::size_type - basic_string::rfind(value_type ch, - size_type pos) const noexcept { - if (pos >= size_) - pos = size_ - 1; - for (auto i = pos; i != 0; --i) { - if (*(buffer_ + i) == ch) - return i; +// 从下标 pos 开始反向查找值为 ch 的元素,与 find 类似 +template +typename basic_string::size_type +basic_string::rfind(value_type ch, + size_type pos) const noexcept { + if (pos >= size_) { + pos = size_ - 1; + } + for (auto i = pos; i != 0; --i) { + if (*(buffer_ + i) == ch) { + return i; } - return front() == ch ? 0 : npos; - } - - // 从下标 pos 开始反向查找字符串 str,与 find 类似 - template - typename basic_string::size_type - basic_string::rfind(const_pointer str, - size_type pos) const noexcept { - if (pos >= size_) - pos = size_ - 1; - const size_type len = char_traits::length(str); - switch (len) { - case 0: - return pos; - case 1: { - for (auto i = pos; i != 0; --i) { - if (*(buffer_ + i) == *str) - return i; + } + return front() == ch ? 0 : npos; +} + +// 从下标 pos 开始反向查找字符串 str,与 find 类似 +template +typename basic_string::size_type +basic_string::rfind(const_pointer str, + size_type pos) const noexcept { + if (pos >= size_) { + pos = size_ - 1; + } + const size_type len = char_traits::length(str); + switch (len) { + case 0: + return pos; + case 1: { + for (auto i = pos; i != 0; --i) { + if (*(buffer_ + i) == *str) { + return i; } - return front() == *str ? 0 : npos; } - default: { // len >= 2 - for (auto i = pos; i >= len - 1; --i) { - if (*(buffer_ + i) == *(str + len - 1)) { - size_type j = 1; - for (; j < len; ++j) { - if (*(buffer_ + i - j) != *(str + len - j - 1)) - break; + return front() == *str ? 0 : npos; + } + default: { // len >= 2 + for (auto i = pos; i >= len - 1; --i) { + if (*(buffer_ + i) == *(str + len - 1)) { + size_type j = 1; + for (; j < len; ++j) { + if (*(buffer_ + i - j) != *(str + len - j - 1)) { + break; } - if (j == len) - return i - len + 1; + } + if (j == len) { + return i - len + 1; } } - break; } + break; } - return npos; } + return npos; +} - // 从下标 pos 开始反向查找字符串 str 前 count 个字符,与 find 类似 - template - typename basic_string::size_type - basic_string::rfind(const_pointer str, size_type pos, - size_type count) const noexcept { - if (count == 0) - return pos; - if (pos >= size_) - pos = size_ - 1; - if (pos < count - 1) - return npos; - for (auto i = pos; i >= count - 1; --i) { - if (*(buffer_ + i) == *(str + count - 1)) { - size_type j = 1; - for (; j < count; ++j) { - if (*(buffer_ + i - j) != *(str + count - j - 1)) - break; - } - if (j == count) - return i - count + 1; - } - } +// 从下标 pos 开始反向查找字符串 str 前 count 个字符,与 find 类似 +template +typename basic_string::size_type +basic_string::rfind(const_pointer str, size_type pos, + size_type count) const noexcept { + if (count == 0) { + return pos; + } + if (pos >= size_) { + pos = size_ - 1; + } + if (pos < count - 1) { return npos; } - - // 从下标 pos 开始反向查找字符串 str,与 find 类似 - template - typename basic_string::size_type - basic_string::rfind(const basic_string &str, - size_type pos) const noexcept { - const size_type count = str.size_; - if (pos >= size_) - pos = size_ - 1; - if (count == 0) - return pos; - if (pos < count - 1) - return npos; - for (auto i = pos; i >= count - 1; --i) { - if (*(buffer_ + i) == str[count - 1]) { - size_type j = 1; - for (; j < count; ++j) { - if (*(buffer_ + i - j) != str[count - j - 1]) - break; + for (auto i = pos; i >= count - 1; --i) { + if (*(buffer_ + i) == *(str + count - 1)) { + size_type j = 1; + for (; j < count; ++j) { + if (*(buffer_ + i - j) != *(str + count - j - 1)) { + break; } - if (j == count) - return i - count + 1; + } + if (j == count) { + return i - count + 1; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找 ch 出现的第一个位置 - template - typename basic_string::size_type - basic_string::find_first_of( - value_type ch, size_type pos) const noexcept { - for (auto i = pos; i < size_; ++i) { - if (*(buffer_ + i) == ch) - return i; - } - return npos; +// 从下标 pos 开始反向查找字符串 str,与 find 类似 +template +typename basic_string::size_type +basic_string::rfind(const basic_string& str, + size_type pos) const noexcept { + const size_type count = str.size_; + if (pos >= size_) { + pos = size_ - 1; } - - // 从下标 pos 开始查找字符串 s 其中的一个字符出现的第一个位置 - template - typename basic_string::size_type - basic_string::find_first_of( - const_pointer s, size_type pos) const noexcept { - const size_type len = char_traits::length(s); - for (auto i = pos; i < size_; ++i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < len; ++j) { - if (ch == *(s + j)) - return i; - } - } - return npos; + if (count == 0) { + return pos; } - - // 从下标 pos 开始查找字符串 s - template - typename basic_string::size_type - basic_string::find_first_of( - const_pointer s, size_type pos, size_type count) const noexcept { - for (auto i = pos; i < size_; ++i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < count; ++j) { - if (ch == *(s + j)) - return i; - } - } + if (pos < count - 1) { return npos; } - - // 从下标 pos 开始查找字符串 str 其中一个字符出现的第一个位置 - template - typename basic_string::size_type - basic_string::find_first_of( - const basic_string &str, size_type pos) const noexcept { - for (auto i = pos; i < size_; ++i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < str.size_; ++j) { - if (ch == str[j]) - return i; + for (auto i = pos; i >= count - 1; --i) { + if (*(buffer_ + i) == str[count - 1]) { + size_type j = 1; + for (; j < count; ++j) { + if (*(buffer_ + i - j) != str[count - j - 1]) { + break; + } + } + if (j == count) { + return i - count + 1; } } - return npos; } - - // 从下标 pos 开始查找与 ch 不相等的第一个位置 - template - typename basic_string::size_type - basic_string::find_first_not_of( - value_type ch, size_type pos) const noexcept { - for (auto i = pos; i < size_; ++i) { - if (*(buffer_ + i) != ch) + return npos; +} + +// 从下标 pos 开始查找 ch 出现的第一个位置 +template +typename basic_string::size_type +basic_string::find_first_of( + value_type ch, size_type pos) const noexcept { + for (auto i = pos; i < size_; ++i) { + if (*(buffer_ + i) == ch) { + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找字符串 s 其中的一个字符出现的第一个位置 +template +typename basic_string::size_type +basic_string::find_first_of( + const_pointer s, size_type pos) const noexcept { + const size_type len = char_traits::length(s); + for (auto i = pos; i < size_; ++i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) { + if (ch == *(s + j)) { return i; - } - return npos; - } - - // 从下标 pos 开始查找与字符串 s 其中一个字符不相等的第一个位置 - template - typename basic_string::size_type - basic_string::find_first_not_of( - const_pointer s, size_type pos) const noexcept { - const size_type len = char_traits::length(s); - for (auto i = pos; i < size_; ++i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < len; ++j) { - if (ch != *(s + j)) - return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的第一个位置 - template - typename basic_string::size_type - basic_string::find_first_not_of( - const_pointer s, size_type pos, size_type count) const noexcept { - for (auto i = pos; i < size_; ++i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < count; ++j) { - if (ch != *(s + j)) - return i; +// 从下标 pos 开始查找字符串 s +template +typename basic_string::size_type +basic_string::find_first_of( + const_pointer s, size_type pos, size_type count) const noexcept { + for (auto i = pos; i < size_; ++i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) { + if (ch == *(s + j)) { + return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找与字符串 str 的字符中不相等的第一个位置 - template - typename basic_string::size_type - basic_string::find_first_not_of( - const basic_string &str, size_type pos) const noexcept { - for (auto i = pos; i < size_; ++i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < str.size_; ++j) { - if (ch != str[j]) - return i; +// 从下标 pos 开始查找字符串 str 其中一个字符出现的第一个位置 +template +typename basic_string::size_type +basic_string::find_first_of( + const basic_string& str, size_type pos) const noexcept { + for (auto i = pos; i < size_; ++i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) { + if (ch == str[j]) { + return i; } } - return npos; } - - // 从下标 pos 开始查找与 ch 相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_of( - value_type ch, size_type pos) const noexcept { - for (auto i = size_ - 1; i >= pos; --i) { - if (*(buffer_ + i) == ch) + return npos; +} + +// 从下标 pos 开始查找与 ch 不相等的第一个位置 +template +typename basic_string::size_type +basic_string::find_first_not_of( + value_type ch, size_type pos) const noexcept { + for (auto i = pos; i < size_; ++i) { + if (*(buffer_ + i) != ch) { + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 其中一个字符不相等的第一个位置 +template +typename basic_string::size_type +basic_string::find_first_not_of( + const_pointer s, size_type pos) const noexcept { + const size_type len = char_traits::length(s); + for (auto i = pos; i < size_; ++i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) { + if (ch != *(s + j)) { return i; - } - return npos; - } - - // 从下标 pos 开始查找与字符串 s 其中一个字符相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_of( - const_pointer s, size_type pos) const noexcept { - const size_type len = char_traits::length(s); - for (auto i = size_ - 1; i >= pos; --i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < len; ++j) { - if (ch == *(s + j)) - return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找与字符串 s 前 count 个字符中相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_of( - const_pointer s, size_type pos, size_type count) const noexcept { - for (auto i = size_ - 1; i >= pos; --i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < count; ++j) { - if (ch == *(s + j)) - return i; +// 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的第一个位置 +template +typename basic_string::size_type +basic_string::find_first_not_of( + const_pointer s, size_type pos, size_type count) const noexcept { + for (auto i = pos; i < size_; ++i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) { + if (ch != *(s + j)) { + return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找与字符串 str 字符中相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_of( - const basic_string &str, size_type pos) const noexcept { - for (auto i = size_ - 1; i >= pos; --i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < str.size_; ++j) { - if (ch == str[j]) - return i; +// 从下标 pos 开始查找与字符串 str 的字符中不相等的第一个位置 +template +typename basic_string::size_type +basic_string::find_first_not_of( + const basic_string& str, size_type pos) const noexcept { + for (auto i = pos; i < size_; ++i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) { + if (ch != str[j]) { + return i; } } - return npos; } - - // 从下标 pos 开始查找与 ch 字符不相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_not_of( - value_type ch, size_type pos) const noexcept { - for (auto i = size_ - 1; i >= pos; --i) { - if (*(buffer_ + i) != ch) + return npos; +} + +// 从下标 pos 开始查找与 ch 相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_of(value_type ch, + size_type pos) const noexcept { + for (auto i = size_ - 1; i >= pos; --i) { + if (*(buffer_ + i) == ch) { + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 其中一个字符相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_of(const_pointer s, + size_type pos) const noexcept { + const size_type len = char_traits::length(s); + for (auto i = size_ - 1; i >= pos; --i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) { + if (ch == *(s + j)) { return i; - } - return npos; - } - - // 从下标 pos 开始查找与字符串 s 的字符中不相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_not_of( - const_pointer s, size_type pos) const noexcept { - const size_type len = char_traits::length(s); - for (auto i = size_ - 1; i >= pos; --i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < len; ++j) { - if (ch != *(s + j)) - return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_not_of( - const_pointer s, size_type pos, size_type count) const noexcept { - for (auto i = size_ - 1; i >= pos; --i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < count; ++j) { - if (ch != *(s + j)) - return i; +// 从下标 pos 开始查找与字符串 s 前 count 个字符中相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_of( + const_pointer s, size_type pos, size_type count) const noexcept { + for (auto i = size_ - 1; i >= pos; --i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) { + if (ch == *(s + j)) { + return i; } } - return npos; } + return npos; +} - // 从下标 pos 开始查找与字符串 str 字符中不相等的最后一个位置 - template - typename basic_string::size_type - basic_string::find_last_not_of( - const basic_string &str, size_type pos) const noexcept { - for (auto i = size_ - 1; i >= pos; --i) { - value_type ch = *(buffer_ + i); - for (size_type j = 0; j < str.size_; ++j) { - if (ch != str[j]) - return i; +// 从下标 pos 开始查找与字符串 str 字符中相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_of(const basic_string& str, + size_type pos) const noexcept { + for (auto i = size_ - 1; i >= pos; --i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) { + if (ch == str[j]) { + return i; } } - return npos; - } - - // 返回从下标 pos 开始字符为 ch 的元素出现的次数 - template - typename basic_string::size_type - basic_string::count(value_type ch, - size_type pos) const noexcept { - size_type n = 0; - for (auto i = pos; i < size_; ++i) { - if (*(buffer_ + i) == ch) - ++n; - } - return n; - } - - /*****************************************************************************************/ - // helper function - - // 尝试初始化一段 buffer,若分配失败则忽略,不会抛出异常 - template - void basic_string::try_init() noexcept { - try { - buffer_ = data_allocator::allocate( - static_cast(STRING_INIT_SIZE)); - size_ = 0; - cap_ = 0; - } catch (...) { - buffer_ = nullptr; - size_ = 0; - cap_ = 0; - // no throw - } } - - // fill_init 函数 - template - void basic_string::fill_init(size_type n, - value_type ch) { - const auto init_size = - mystl::max(static_cast(STRING_INIT_SIZE), n + 1); - buffer_ = data_allocator::allocate(init_size); - char_traits::fill(buffer_, ch, n); - size_ = n; - cap_ = init_size; - } - - // copy_init 函数 - template - template - void - basic_string::copy_init(Iter first, Iter last, - mystl::input_iterator_tag) { - size_type n = mystl::distance(first, last); - const auto init_size = - mystl::max(static_cast(STRING_INIT_SIZE), n + 1); - try { - buffer_ = data_allocator::allocate(init_size); - size_ = n; - cap_ = init_size; - } catch (...) { - buffer_ = nullptr; - size_ = 0; - cap_ = 0; - throw; - } - for (; n > 0; --n, ++first) - append(*first); - } - - template - template - void - basic_string::copy_init(Iter first, Iter last, - mystl::forward_iterator_tag) { - const size_type n = mystl::distance(first, last); - const auto init_size = - mystl::max(static_cast(STRING_INIT_SIZE), n + 1); - try { - buffer_ = data_allocator::allocate(init_size); - size_ = n; - cap_ = init_size; - mystl::uninitialized_copy(first, last, buffer_); - } catch (...) { - buffer_ = nullptr; - size_ = 0; - cap_ = 0; - throw; - } - } - - // init_from 函数 - template - void basic_string::init_from(const_pointer src, - size_type pos, - size_type count) { - const auto init_size = - mystl::max(static_cast(STRING_INIT_SIZE), count + 1); - buffer_ = data_allocator::allocate(init_size); - char_traits::copy(buffer_, src + pos, count); - size_ = count; - cap_ = init_size; - } - - // destroy_buffer 函数 - template - void basic_string::destroy_buffer() { - if (buffer_ != nullptr) { - data_allocator::deallocate(buffer_, cap_); - buffer_ = nullptr; - size_ = 0; - cap_ = 0; - } - } - - // to_raw_pointer 函数 - template - typename basic_string::const_pointer - basic_string::to_raw_pointer() const { - *(buffer_ + size_) = value_type(); - return buffer_; - } - - // reinsert 函数 - template - void basic_string::reinsert(size_type size) { - auto new_buffer = data_allocator::allocate(size); - try { - char_traits::move(new_buffer, buffer_, size); - } catch (...) { data_allocator::deallocate(new_buffer); } - buffer_ = new_buffer; - size_ = size; - cap_ = size; - } - - // append_range,末尾追加一段 [first, last) 内的字符 - template - template - basic_string & - basic_string::append_range(Iter first, Iter last) { - const size_type n = mystl::distance(first, last); - THROW_LENGTH_ERROR_IF(size_ > max_size() - n, - "basic_string's size too big"); - if (cap_ - size_ < n) { - reallocate(n); - } - mystl::uninitialized_copy_n(first, n, buffer_ + size_); - size_ += n; - return *this; - } - - template - int basic_string::compare_cstr(const_pointer s1, - size_type n1, - const_pointer s2, - size_type n2) const { - auto rlen = mystl::min(n1, n2); - auto res = char_traits::compare(s1, s2, rlen); - if (res != 0) - return res; - if (n1 < n2) - return -1; - if (n1 > n2) - return 1; - return 0; - } - - // 把 first 开始的 count1 个字符替换成 str 开始的 count2 个字符 - template - basic_string & - basic_string::replace_cstr(const_iterator first, - size_type count1, - const_pointer str, - size_type count2) { - if (static_cast(cend() - first) < count1) { - count1 = cend() - first; - } - if (count1 < count2) { - const size_type add = count2 - count1; - THROW_LENGTH_ERROR_IF(size_ > max_size() - add, - "basic_string's size too big"); - if (size_ > cap_ - add) { - reallocate(add); + return npos; +} + +// 从下标 pos 开始查找与 ch 字符不相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_not_of( + value_type ch, size_type pos) const noexcept { + for (auto i = size_ - 1; i >= pos; --i) { + if (*(buffer_ + i) != ch) { + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 的字符中不相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_not_of( + const_pointer s, size_type pos) const noexcept { + const size_type len = char_traits::length(s); + for (auto i = size_ - 1; i >= pos; --i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) { + if (ch != *(s + j)) { + return i; } - pointer r = const_cast(first); - char_traits::move(r + count2, first + count1, - end() - (first + count1)); - char_traits::copy(r, str, count2); - size_ += add; } - else { - pointer r = const_cast(first); - char_traits::move(r + count2, first + count1, - end() - (first + count1)); - char_traits::copy(r, str, count2); - size_ -= (count1 - count2); - } - return *this; } + return npos; +} - // 把 first 开始的 count1 个字符替换成 count2 个 ch 字符 - template - basic_string & - basic_string::replace_fill(const_iterator first, - size_type count1, - size_type count2, - value_type ch) { - if (static_cast(cend() - first) < count1) { - count1 = cend() - first; - } - if (count1 < count2) { - const size_type add = count2 - count1; - THROW_LENGTH_ERROR_IF(size_ > max_size() - add, - "basic_string's size too big"); - if (size_ > cap_ - add) { - reallocate(add); +// 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_not_of( + const_pointer s, size_type pos, size_type count) const noexcept { + for (auto i = size_ - 1; i >= pos; --i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) { + if (ch != *(s + j)) { + return i; } - pointer r = const_cast(first); - char_traits::move(r + count2, first + count1, - end() - (first + count1)); - char_traits::fill(r, ch, count2); - size_ += add; } - else { - pointer r = const_cast(first); - char_traits::move(r + count2, first + count1, - end() - (first + count1)); - char_traits::fill(r, ch, count2); - size_ -= (count1 - count2); - } - return *this; } + return npos; +} - // 把 [first, last) 的字符替换成 [first2, last2) - template - template - basic_string & - basic_string::replace_copy(const_iterator first, - const_iterator last, - Iter first2, Iter last2) { - size_type len1 = last - first; - size_type len2 = last2 - first2; - if (len1 < len2) { - const size_type add = len2 - len1; - THROW_LENGTH_ERROR_IF(size_ > max_size() - add, - "basic_string's size too big"); - if (size_ > cap_ - add) { - reallocate(add); +// 从下标 pos 开始查找与字符串 str 字符中不相等的最后一个位置 +template +typename basic_string::size_type +basic_string::find_last_not_of( + const basic_string& str, size_type pos) const noexcept { + for (auto i = size_ - 1; i >= pos; --i) { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) { + if (ch != str[j]) { + return i; } - pointer r = const_cast(first); - char_traits::move(r + len2, first + len1, end() - (first + len1)); - char_traits::copy(r, first2, len2); - size_ += add; } - else { - pointer r = const_cast(first); - char_traits::move(r + len2, first + len1, end() - (first + len1)); - char_traits::copy(r, first2, len2); - size_ -= (len1 - len2); - } - return *this; } - - // reallocate 函数 - template - void basic_string::reallocate(size_type need) { - const auto new_cap = mystl::max(cap_ + need, cap_ + (cap_ >> 1)); - auto new_buffer = data_allocator::allocate(new_cap); - char_traits::move(new_buffer, buffer_, size_); - data_allocator::deallocate(buffer_); - buffer_ = new_buffer; - cap_ = new_cap; - } - - // reallocate_and_fill 函数 - template - typename basic_string::iterator - basic_string::reallocate_and_fill(iterator pos, - size_type n, - value_type ch) { - const auto r = pos - buffer_; - const auto old_cap = cap_; - const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1)); - auto new_buffer = data_allocator::allocate(new_cap); - auto e1 = char_traits::move(new_buffer, buffer_, r) + r; - auto e2 = char_traits::fill(e1, ch, n) + n; - char_traits::move(e2, buffer_ + r, size_ - r); - data_allocator::deallocate(buffer_, old_cap); - buffer_ = new_buffer; - size_ += n; - cap_ = new_cap; - return buffer_ + r; - } - - // reallocate_and_copy 函数 - template - typename basic_string::iterator - basic_string::reallocate_and_copy( - iterator pos, const_iterator first, const_iterator last) { - const auto r = pos - buffer_; - const auto old_cap = cap_; - const size_type n = mystl::distance(first, last); - const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1)); - auto new_buffer = data_allocator::allocate(new_cap); - auto e1 = char_traits::move(new_buffer, buffer_, r) + r; - auto e2 = mystl::uninitialized_copy_n(first, n, e1) + n; - char_traits::move(e2, buffer_ + r, size_ - r); - data_allocator::deallocate(buffer_, old_cap); - buffer_ = new_buffer; - size_ += n; - cap_ = new_cap; - return buffer_ + r; - } - - /*****************************************************************************************/ - // 重载全局操作符 - - // 重载 operator+ - template - basic_string - operator+(const basic_string &lhs, - const basic_string &rhs) { - basic_string tmp(lhs); - tmp.append(rhs); - return tmp; - } - - template - basic_string - operator+(const CharType * lhs, - const basic_string &rhs) { - basic_string tmp(lhs); - tmp.append(rhs); - return tmp; - } - - template - basic_string - operator+(CharType ch, const basic_string &rhs) { - basic_string tmp(1, ch); - tmp.append(rhs); - return tmp; - } - - template - basic_string - operator+(const basic_string &lhs, - const CharType * rhs) { - basic_string tmp(lhs); - tmp.append(rhs); - return tmp; - } - - template - basic_string - operator+(const basic_string &lhs, CharType ch) { - basic_string tmp(lhs); - tmp.append(1, ch); - return tmp; - } - - template - basic_string - operator+(basic_string && lhs, - const basic_string &rhs) { - basic_string tmp(mystl::move(lhs)); - tmp.append(rhs); - return tmp; - } - - template - basic_string - operator+(const basic_string &lhs, - basic_string && rhs) { - basic_string tmp(mystl::move(rhs)); - tmp.insert(tmp.begin(), lhs.begin(), lhs.end()); - return tmp; - } - - template - basic_string - operator+(basic_string &&lhs, - basic_string &&rhs) { - basic_string tmp(mystl::move(lhs)); - tmp.append(rhs); - return tmp; - } - - template - basic_string - operator+(const CharType *lhs, basic_string &&rhs) { - basic_string tmp(mystl::move(rhs)); - tmp.insert(tmp.begin(), lhs, lhs + char_traits::length(lhs)); - return tmp; - } - - template - basic_string - operator+(CharType ch, basic_string &&rhs) { - basic_string tmp(mystl::move(rhs)); - tmp.insert(tmp.begin(), ch); - return tmp; - } - - template - basic_string - operator+(basic_string &&lhs, const CharType *rhs) { - basic_string tmp(mystl::move(lhs)); - tmp.append(rhs); - return tmp; - } - - template - basic_string - operator+(basic_string &&lhs, CharType ch) { - basic_string tmp(mystl::move(lhs)); - tmp.append(1, ch); - return tmp; - } - - // 重载比较操作符 - template - bool operator==(const basic_string &lhs, - const basic_string &rhs) { - return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; - } - - template - bool operator!=(const basic_string &lhs, - const basic_string &rhs) { - return lhs.size() != rhs.size() || lhs.compare(rhs) != 0; - } - - template - bool operator<(const basic_string &lhs, - const basic_string &rhs) { - return lhs.compare(rhs) < 0; - } - - template - bool operator<=(const basic_string &lhs, - const basic_string &rhs) { - return lhs.compare(rhs) <= 0; - } - - template - bool operator>(const basic_string &lhs, - const basic_string &rhs) { - return lhs.compare(rhs) > 0; - } - - template - bool operator>=(const basic_string &lhs, - const basic_string &rhs) { - return lhs.compare(rhs) >= 0; - } - - // 重载 mystl 的 swap - template - void swap(basic_string &lhs, - basic_string &rhs) noexcept { - lhs.swap(rhs); + return npos; +} + +// 返回从下标 pos 开始字符为 ch 的元素出现的次数 +template +typename basic_string::size_type +basic_string::count(value_type ch, + size_type pos) const noexcept { + size_type n = 0; + for (auto i = pos; i < size_; ++i) { + if (*(buffer_ + i) == ch) { + ++n; + } + } + return n; +} + +/*****************************************************************************************/ +// helper function + +// 尝试初始化一段 buffer,若分配失败则忽略,不会抛出异常 +template +void basic_string::try_init() noexcept { + try { + buffer_ + = data_allocator::allocate(static_cast(STRING_INIT_SIZE)); + size_ = 0; + cap_ = 0; + } catch (...) { + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + // no throw + } +} + +// fill_init 函数 +template +void basic_string::fill_init(size_type n, value_type ch) { + const auto init_size + = mystl::max(static_cast(STRING_INIT_SIZE), n + 1); + buffer_ = data_allocator::allocate(init_size); + char_traits::fill(buffer_, ch, n); + size_ = n; + cap_ = init_size; +} + +// copy_init 函数 +template +template +void basic_string::copy_init(Iter first, Iter last, + mystl::input_iterator_tag) { + size_type n = mystl::distance(first, last); + const auto init_size + = mystl::max(static_cast(STRING_INIT_SIZE), n + 1); + try { + buffer_ = data_allocator::allocate(init_size); + size_ = n; + cap_ = init_size; + } catch (...) { + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + throw; + } + for (; n > 0; --n, ++first) { + append(*first); + } +} + +template +template +void basic_string::copy_init( + Iter first, Iter last, mystl::forward_iterator_tag) { + const size_type n = mystl::distance(first, last); + const auto init_size + = mystl::max(static_cast(STRING_INIT_SIZE), n + 1); + try { + buffer_ = data_allocator::allocate(init_size); + size_ = n; + cap_ = init_size; + mystl::uninitialized_copy(first, last, buffer_); + } catch (...) { + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + throw; + } +} + +// init_from 函数 +template +void basic_string::init_from(const_pointer src, + size_type pos, + size_type count) { + const auto init_size + = mystl::max(static_cast(STRING_INIT_SIZE), count + 1); + buffer_ = data_allocator::allocate(init_size); + char_traits::copy(buffer_, src + pos, count); + size_ = count; + cap_ = init_size; +} + +// destroy_buffer 函数 +template +void basic_string::destroy_buffer() { + if (buffer_ != nullptr) { + data_allocator::deallocate(buffer_, cap_); + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + } +} + +// to_raw_pointer 函数 +template +typename basic_string::const_pointer +basic_string::to_raw_pointer() const { + *(buffer_ + size_) = value_type(); + return buffer_; +} + +// reinsert 函数 +template +void basic_string::reinsert(size_type size) { + auto new_buffer = data_allocator::allocate(size); + try { + char_traits::move(new_buffer, buffer_, size); + } catch (...) { + data_allocator::deallocate(new_buffer); + } + buffer_ = new_buffer; + size_ = size; + cap_ = size; +} + +// append_range,末尾追加一段 [first, last) 内的字符 +template +template +basic_string& +basic_string::append_range(Iter first, Iter last) { + const size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, + "basic_string's size too big"); + if (cap_ - size_ < n) { + reallocate(n); + } + mystl::uninitialized_copy_n(first, n, buffer_ + size_); + size_ += n; + return *this; +} + +template +int basic_string::compare_cstr(const_pointer s1, + size_type n1, + const_pointer s2, + size_type n2) const { + auto rlen = mystl::min(n1, n2); + auto res = char_traits::compare(s1, s2, rlen); + if (res != 0) { + return res; + } + if (n1 < n2) { + return -1; + } + if (n1 > n2) { + return 1; + } + return 0; +} + +// 把 first 开始的 count1 个字符替换成 str 开始的 count2 个字符 +template +basic_string& +basic_string::replace_cstr(const_iterator first, + size_type count1, + const_pointer str, + size_type count2) { + if (static_cast(cend() - first) < count1) { + count1 = cend() - first; + } + if (count1 < count2) { + const size_type add = count2 - count1; + THROW_LENGTH_ERROR_IF(size_ > max_size() - add, + "basic_string's size too big"); + if (size_ > cap_ - add) { + reallocate(add); + } + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::copy(r, str, count2); + size_ += add; + } + else { + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::copy(r, str, count2); + size_ -= (count1 - count2); + } + return *this; +} + +// 把 first 开始的 count1 个字符替换成 count2 个 ch 字符 +template +basic_string& +basic_string::replace_fill(const_iterator first, + size_type count1, + size_type count2, + value_type ch) { + if (static_cast(cend() - first) < count1) { + count1 = cend() - first; + } + if (count1 < count2) { + const size_type add = count2 - count1; + THROW_LENGTH_ERROR_IF(size_ > max_size() - add, + "basic_string's size too big"); + if (size_ > cap_ - add) { + reallocate(add); + } + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::fill(r, ch, count2); + size_ += add; + } + else { + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::fill(r, ch, count2); + size_ -= (count1 - count2); + } + return *this; +} + +// 把 [first, last) 的字符替换成 [first2, last2) +template +template +basic_string& +basic_string::replace_copy(const_iterator first, + const_iterator last, + Iter first2, Iter last2) { + size_type len1 = last - first; + size_type len2 = last2 - first2; + if (len1 < len2) { + const size_type add = len2 - len1; + THROW_LENGTH_ERROR_IF(size_ > max_size() - add, + "basic_string's size too big"); + if (size_ > cap_ - add) { + reallocate(add); + } + pointer r = const_cast(first); + char_traits::move(r + len2, first + len1, end() - (first + len1)); + char_traits::copy(r, first2, len2); + size_ += add; + } + else { + pointer r = const_cast(first); + char_traits::move(r + len2, first + len1, end() - (first + len1)); + char_traits::copy(r, first2, len2); + size_ -= (len1 - len2); + } + return *this; +} + +// reallocate 函数 +template +void basic_string::reallocate(size_type need) { + const auto new_cap = mystl::max(cap_ + need, cap_ + (cap_ >> 1)); + auto new_buffer = data_allocator::allocate(new_cap); + char_traits::move(new_buffer, buffer_, size_); + data_allocator::deallocate(buffer_); + buffer_ = new_buffer; + cap_ = new_cap; +} + +// reallocate_and_fill 函数 +template +typename basic_string::iterator +basic_string::reallocate_and_fill(iterator pos, + size_type n, + value_type ch) { + const auto r = pos - buffer_; + const auto old_cap = cap_; + const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1)); + auto new_buffer = data_allocator::allocate(new_cap); + auto e1 = char_traits::move(new_buffer, buffer_, r) + r; + auto e2 = char_traits::fill(e1, ch, n) + n; + char_traits::move(e2, buffer_ + r, size_ - r); + data_allocator::deallocate(buffer_, old_cap); + buffer_ = new_buffer; + size_ += n; + cap_ = new_cap; + return buffer_ + r; +} + +// reallocate_and_copy 函数 +template +typename basic_string::iterator +basic_string::reallocate_and_copy(iterator pos, + const_iterator first, + const_iterator last) { + const auto r = pos - buffer_; + const auto old_cap = cap_; + const size_type n = mystl::distance(first, last); + const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1)); + auto new_buffer = data_allocator::allocate(new_cap); + auto e1 = char_traits::move(new_buffer, buffer_, r) + r; + auto e2 = mystl::uninitialized_copy_n(first, n, e1) + n; + char_traits::move(e2, buffer_ + r, size_ - r); + data_allocator::deallocate(buffer_, old_cap); + buffer_ = new_buffer; + size_ += n; + cap_ = new_cap; + return buffer_ + r; +} + +/*****************************************************************************************/ +// 重载全局操作符 + +// 重载 operator+ +template +basic_string +operator+(const basic_string& lhs, + const basic_string& rhs) { + basic_string tmp(lhs); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const CharType* lhs, const basic_string& rhs) { + basic_string tmp(lhs); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(CharType ch, const basic_string& rhs) { + basic_string tmp(1, ch); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const basic_string& lhs, const CharType* rhs) { + basic_string tmp(lhs); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const basic_string& lhs, CharType ch) { + basic_string tmp(lhs); + tmp.append(1, ch); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, + const basic_string& rhs) { + basic_string tmp(mystl::move(lhs)); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const basic_string& lhs, + basic_string&& rhs) { + basic_string tmp(mystl::move(rhs)); + tmp.insert(tmp.begin(), lhs.begin(), lhs.end()); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, + basic_string&& rhs) { + basic_string tmp(mystl::move(lhs)); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const CharType* lhs, basic_string&& rhs) { + basic_string tmp(mystl::move(rhs)); + tmp.insert(tmp.begin(), lhs, lhs + char_traits::length(lhs)); + return tmp; +} + +template +basic_string +operator+(CharType ch, basic_string&& rhs) { + basic_string tmp(mystl::move(rhs)); + tmp.insert(tmp.begin(), ch); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, const CharType* rhs) { + basic_string tmp(mystl::move(lhs)); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, CharType ch) { + basic_string tmp(mystl::move(lhs)); + tmp.append(1, ch); + return tmp; +} + +// 重载比较操作符 +template +bool operator==(const basic_string& lhs, + const basic_string& rhs) { + return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; +} + +template +bool operator!=(const basic_string& lhs, + const basic_string& rhs) { + return lhs.size() != rhs.size() || lhs.compare(rhs) != 0; +} + +template +bool operator<(const basic_string& lhs, + const basic_string& rhs) { + return lhs.compare(rhs) < 0; +} + +template +bool operator<=(const basic_string& lhs, + const basic_string& rhs) { + return lhs.compare(rhs) <= 0; +} + +template +bool operator>(const basic_string& lhs, + const basic_string& rhs) { + return lhs.compare(rhs) > 0; +} + +template +bool operator>=(const basic_string& lhs, + const basic_string& rhs) { + return lhs.compare(rhs) >= 0; +} + +// 重载 mystl 的 swap +template +void swap(basic_string& lhs, + basic_string& rhs) noexcept { + lhs.swap(rhs); +} + +// 特化 mystl::hash +template +struct hash> { + size_t operator()(const basic_string& str) { + return bitwise_hash((const unsigned char*)str.c_str(), + str.size() * sizeof(CharType)); } - - // 特化 mystl::hash - template - struct hash> { - size_t operator()(const basic_string &str) { - return bitwise_hash((const unsigned char *)str.c_str(), - str.size() * sizeof(CharType)); - } - }; - }; -#endif /* _BASIC_STRING_ */ +}; // namespace mystl + +#endif /* SIMPLEKERNEL_BASIC_STRING */ diff --git a/src/libcxx/include/cassert b/src/libcxx/include/cassert new file mode 100644 index 000000000..f73a8ae33 --- /dev/null +++ b/src/libcxx/include/cassert @@ -0,0 +1,31 @@ + +/** + * @file cassert + * @brief assert 实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * Based on https://wiki.osdev.org/Raspberry_Pi_Bare_Bones + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CASSERT +#define SIMPLEKERNEL_CASSERT + +#ifdef __cplusplus +extern "C" { +#endif + +#include "assert.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CASSERT */ diff --git a/src/libcxx/include/cfloat b/src/libcxx/include/cfloat new file mode 100644 index 000000000..4004a0d29 --- /dev/null +++ b/src/libcxx/include/cfloat @@ -0,0 +1,30 @@ + +/** + * @file cfloat + * @brief float 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CFLOAT +#define SIMPLEKERNEL_CFLOAT + +#ifdef __cplusplus +extern "C" { +#endif + +#include "float.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CFLOAT */ diff --git a/src/libcxx/include/climits b/src/libcxx/include/climits new file mode 100644 index 000000000..469c11efc --- /dev/null +++ b/src/libcxx/include/climits @@ -0,0 +1,30 @@ + +/** + * @file climits + * @brief limits 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CLIMITS +#define SIMPLEKERNEL_CLIMITS + +#ifdef __cplusplus +extern "C" { +#endif + +#include "limits.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CLIMITS */ diff --git a/src/libcxx/include/cmath b/src/libcxx/include/cmath new file mode 100644 index 000000000..28ba254a3 --- /dev/null +++ b/src/libcxx/include/cmath @@ -0,0 +1,30 @@ + +/** + * @file cmath + * @brief math 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CMATH +#define SIMPLEKERNEL_CMATH + +#ifdef __cplusplus +extern "C" { +#endif + +#include "math.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CMATH */ diff --git a/src/libcxx/include/construct b/src/libcxx/include/construct index 0e1c10432..611f56db4 100644 --- a/src/libcxx/include/construct +++ b/src/libcxx/include/construct @@ -1,73 +1,85 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// construct for Simple-XX/SimpleKernel. - -#ifndef _CONSTRUCT_ -#define _CONSTRUCT_ +/** + * @file construct + * @brief stl construct 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_CONSTRUCT +#define SIMPLEKERNEL_CONSTRUCT // 这个头文件包含两个函数 construct,destroy // construct : 负责对象的构造 // destroy : 负责对象的析构 +#include "iterator" #include "new" #include "type_traits" -#include "iterator" namespace mystl { - // construct 构造对象 +// construct 构造对象 - template - void construct(Ty *ptr) { - ::new ((void *)ptr) Ty(); - } +template +void construct(Ty* ptr) { + ::new ((void*)ptr) Ty(); +} - template - void construct(Ty1 *ptr, const Ty2 &value) { - ::new ((void *)ptr) Ty1(value); - } +template +void construct(Ty1* ptr, const Ty2& value) { + ::new ((void*)ptr) Ty1(value); +} - template - void construct(Ty *ptr, Args &&...args) { - ::new ((void *)ptr) Ty(mystl::forward(args)...); - } +template +void construct(Ty* ptr, Args&&... args) { + ::new ((void*)ptr) Ty(mystl::forward(args)...); +} - // destroy 将对象析构 +// destroy 将对象析构 - template - void destroy_one(Ty *, std::true_type) { - } +template +void destroy_one(Ty*, std::true_type) { +} - template - void destroy_one(Ty *pointer, std::false_type) { - if (pointer != nullptr) { - pointer->~Ty(); - } +template +void destroy_one(Ty* pointer, std::false_type) { + if (pointer != nullptr) { + pointer->~Ty(); } +} - template - void destroy_cat(ForwardIter, ForwardIter, std::true_type) { - } +template +void destroy_cat(ForwardIter, ForwardIter, std::true_type) { +} - template - void destroy(Ty *pointer) { - destroy_one(pointer, std::is_trivially_destructible{}); - } +template +void destroy(Ty* pointer) { + destroy_one(pointer, std::is_trivially_destructible {}); +} - template - void destroy_cat(ForwardIter first, ForwardIter last, std::false_type) { - for (; first != last; ++first) - destroy(&*first); +template +void destroy_cat(ForwardIter first, ForwardIter last, std::false_type) { + for (; first != last; ++first) { + destroy(&*first); } +} - template - void destroy(ForwardIter first, ForwardIter last) { - destroy_cat(first, last, - std::is_trivially_destructible< - typename iterator_traits::value_type>{}); - } -}; +template +void destroy(ForwardIter first, ForwardIter last) { + destroy_cat(first, last, + std::is_trivially_destructible< + typename iterator_traits::value_type> {}); +} +}; // namespace mystl -#endif /* _CONSTRUCT_ */ +#endif /* SIMPLEKERNEL_CONSTRUCT */ diff --git a/src/libcxx/include/cstdarg b/src/libcxx/include/cstdarg new file mode 100644 index 000000000..113f4ce75 --- /dev/null +++ b/src/libcxx/include/cstdarg @@ -0,0 +1,30 @@ + +/** + * @file cstdarg + * @brief stdarg 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CSTDARG +#define SIMPLEKERNEL_CSTDARG + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdarg.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CSTDARG */ diff --git a/src/libcxx/include/cstdbool b/src/libcxx/include/cstdbool new file mode 100644 index 000000000..887976188 --- /dev/null +++ b/src/libcxx/include/cstdbool @@ -0,0 +1,30 @@ + +/** + * @file cstdbool + * @brief stdbool 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CSTDBOOL +#define SIMPLEKERNEL_CSTDBOOL + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdbool.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CSTDBOOL */ diff --git a/src/libcxx/include/cstddef b/src/libcxx/include/cstddef new file mode 100644 index 000000000..2c44e953f --- /dev/null +++ b/src/libcxx/include/cstddef @@ -0,0 +1,30 @@ + +/** + * @file cstddef + * @brief stddef 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CSTDDEF +#define SIMPLEKERNEL_CSTDDEF + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stddef.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CSTDDEF */ diff --git a/src/libcxx/include/cstdint b/src/libcxx/include/cstdint new file mode 100644 index 000000000..8ea2ad60d --- /dev/null +++ b/src/libcxx/include/cstdint @@ -0,0 +1,31 @@ + +/** + * @file cstdint + * @brief stdint 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * Based on GNU C Lib + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CSTDINT +#define SIMPLEKERNEL_CSTDINT + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdint.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CSTDINT */ diff --git a/src/libcxx/include/cstdio b/src/libcxx/include/cstdio new file mode 100644 index 000000000..ae5fc5f4e --- /dev/null +++ b/src/libcxx/include/cstdio @@ -0,0 +1,31 @@ + +/** + * @file cstdio + * @brief stdio 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * Based on https://github.com/mpaland/printf + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CSTDIO +#define SIMPLEKERNEL_CSTDIO + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdio.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CSTDIO */ diff --git a/src/libcxx/include/cstdlib b/src/libcxx/include/cstdlib new file mode 100644 index 000000000..24fd88274 --- /dev/null +++ b/src/libcxx/include/cstdlib @@ -0,0 +1,30 @@ + +/** + * @file cstdlib + * @brief stdlib 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CSTDLIB +#define SIMPLEKERNEL_CSTDLIB + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CSTDLIB */ diff --git a/src/libcxx/include/cstring b/src/libcxx/include/cstring index 1bf325d09..4f702c729 100644 --- a/src/libcxx/include/cstring +++ b/src/libcxx/include/cstring @@ -1,11 +1,22 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/gcc-mirror/gcc -// cstring for Simple-XX/SimpleKernel. +/** + * @file cstring + * @brief string 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ -#ifndef _CSTRING_ -#define _CSTRING_ +#ifndef SIMPLEKERNEL_CSTRING +#define SIMPLEKERNEL_CSTRING // -*- C++ -*- forwarding header. @@ -71,44 +82,44 @@ #undef strtok #undef strxfrm -inline void *memchr(void *__s, int __c, size_t __n) { +inline void* memchr(void* __s, int __c, size_t __n) { return __builtin_memchr(__s, __c, __n); } -inline char *strchr(char *__s, int __n) { +inline char* strchr(char* __s, int __n) { return __builtin_strchr(__s, __n); } -inline char *strpbrk(char *__s1, const char *__s2) { +inline char* strpbrk(char* __s1, const char* __s2) { return __builtin_strpbrk(__s1, __s2); } -inline char *strrchr(char *__s, int __n) { +inline char* strrchr(char* __s, int __n) { return __builtin_strrchr(__s, __n); } -inline char *strstr(char *__s1, const char *__s2) { +inline char* strstr(char* __s1, const char* __s2) { return __builtin_strstr(__s1, __s2); } namespace std { - using ::memchr; - using ::memcmp; - using ::memcpy; - using ::memmove; - using ::memset; - using ::strcat; - using ::strchr; - using ::strcmp; - using ::strcpy; - using ::strlen; - using ::strncmp; - using ::strncpy; - using ::strpbrk; - using ::strrchr; - using ::strstr; - -}; - -#endif /* cstring */ +using ::memchr; +using ::memcmp; +using ::memcpy; +using ::memmove; +using ::memset; +using ::strcat; +using ::strchr; +using ::strcmp; +using ::strcpy; +using ::strlen; +using ::strncmp; +using ::strncpy; +using ::strpbrk; +using ::strrchr; +using ::strstr; + +}; // namespace std + +#endif /* SIMPLEKERNEL_CSTRING */ diff --git a/src/libcxx/include/ctype b/src/libcxx/include/ctype new file mode 100644 index 000000000..1b4ff308d --- /dev/null +++ b/src/libcxx/include/ctype @@ -0,0 +1,30 @@ + +/** + * @file ctype + * @brief ctype 定义 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#ifndef SIMPLEKERNEL_CTYPE +#define SIMPLEKERNEL_CTYPE + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ctype.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SIMPLEKERNEL_CTYPE */ diff --git a/src/libcxx/include/cxxabi.h b/src/libcxx/include/cxxabi.h index f9b174319..962b4afd4 100644 --- a/src/libcxx/include/cxxabi.h +++ b/src/libcxx/include/cxxabi.h @@ -1,11 +1,22 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://wiki.osdev.org/C%2B%2B -// cxxabi.h for Simple-XX/SimpleKernel. - -#ifndef _CXXABI_H_ -#define _CXXABI_H_ +/** + * @file cxxabi.h + * @brief C++ abi 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://wiki.osdev.org/C%2B%2B + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_CXXABI_H +#define SIMPLEKERNEL_CXXABI_H #ifdef __cplusplus extern "C" { @@ -14,11 +25,17 @@ extern "C" { // c++ 初始化 void cpp_init(void); -int __cxa_atexit(void (*f)(void *), void *objptr, void *dso); -void __cxa_finalize(void *f); +int __cxa_atexit(void (*f)(void*), void* objptr, void* dso); +void __cxa_finalize(void* f); + +int __aeabi_atexit(void (*f)(void*), void* objptr, void* dso); +void __cxa_finalize(void* f); -int __aeabi_atexit(void (*f)(void *), void *objptr, void *dso); -void __cxa_finalize(void *f); +#if UINT32_MAX == UINTPTR_MAX +# define STACK_CHK_GUARD 0xe2dee396 +#else +# define STACK_CHK_GUARD 0x595e9fbd94fda766 +#endif #ifdef __cplusplus }; @@ -26,34 +43,35 @@ void __cxa_finalize(void *f); namespace std { class type_info { - private: - const char *tname; + const char* tname; public: virtual ~type_info(void); - type_info(const type_info &); + type_info(const type_info&); - explicit type_info(const char *); + explicit type_info(const char*); - const char *name(void) const; + const char* name(void) const; - bool operator==(const type_info &) const; + bool operator==(const type_info&) const; - bool operator!=(const type_info &) const; + bool operator!=(const type_info&) const; }; -} // namespace std +} // namespace std namespace __cxxabiv1 { -#define ADD_CXX_TYPEINFO_HEADER(t) \ - class t : public std::type_info { \ - private: \ - protected: \ - public: \ - explicit t(const char *); \ - virtual ~t(void); \ +#define ADD_CXX_TYPEINFO_HEADER(t) \ + class t : public std::type_info { \ + private: \ + \ + protected: \ + \ + public: \ + explicit t(const char*); \ + virtual ~t(void); \ } ADD_CXX_TYPEINFO_HEADER(__fundamental_type_info); @@ -68,6 +86,6 @@ ADD_CXX_TYPEINFO_HEADER(__si_class_type_info); ADD_CXX_TYPEINFO_HEADER(__vmi_class_type_info); #undef ADD_CXX_TYPEINFO_HEADER -} // namespace __cxxabiv1 +} // namespace __cxxabiv1 -#endif /* _CXXABI_H_ */ +#endif /* SIMPLEKERNEL_CXXABI_H */ diff --git a/src/libcxx/include/deque b/src/libcxx/include/deque index bf0e08c7f..0e4e4a985 100644 --- a/src/libcxx/include/deque +++ b/src/libcxx/include/deque @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// deque for Simple-XX/SimpleKernel. - -#ifndef _DEQUE_ -#define _DEQUE_ +/** + * @file deque + * @brief stl deque 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_DEQUE +#define SIMPLEKERNEL_DEQUE // 这个头文件包含了一个模板类 deque // deque: 双端队列 @@ -22,1288 +33,1334 @@ // * push_back // * insert +#include "exceptdef" #include "initializer_list" #include "iterator" #include "memory" #include "util" -#include "exceptdef" namespace mystl { #ifdef max -#pragma message("#undefing marco max") -#undef max -#endif // max +# pragma message("#undefing marco max") +# undef max +#endif // max #ifdef min -#pragma message("#undefing marco min") -#undef min -#endif // min +# pragma message("#undefing marco min") +# undef min +#endif // min // deque map 初始化的大小 #ifndef DEQUE_MAP_INIT_SIZE -#define DEQUE_MAP_INIT_SIZE 8 +# define DEQUE_MAP_INIT_SIZE 8 #endif - template - struct deque_buf_size { - static constexpr size_t value = sizeof(T) < 256 ? 4096 / sizeof(T) : 16; - }; - - // deque 的迭代器设计 - template - struct deque_iterator : public iterator { - typedef deque_iterator iterator; - typedef deque_iterator const_iterator; - typedef deque_iterator self; - - typedef T value_type; - typedef Ptr pointer; - typedef Ref reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T * value_pointer; - typedef T ** map_pointer; - - static const size_type buffer_size = deque_buf_size::value; - - // 迭代器所含成员数据 - value_pointer cur; // 指向所在缓冲区的当前元素 - value_pointer first; // 指向所在缓冲区的头部 - value_pointer last; // 指向所在缓冲区的尾部 - map_pointer node; // 缓冲区所在节点 - - // 构造、复制、移动函数 - deque_iterator() noexcept - : cur(nullptr), first(nullptr), last(nullptr), node(nullptr) { - } +template +struct deque_buf_size { + static constexpr size_t value = sizeof(T) < 256 ? 4096 / sizeof(T) : 16; +}; - deque_iterator(value_pointer v, map_pointer n) - : cur(v), first(*n), last(*n + buffer_size), node(n) { - } +// deque 的迭代器设计 +template +struct deque_iterator : public iterator { + typedef deque_iterator iterator; + typedef deque_iterator const_iterator; + typedef deque_iterator self; + + typedef T value_type; + typedef Ptr pointer; + typedef Ref reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* value_pointer; + typedef T** map_pointer; + + static const size_type buffer_size = deque_buf_size::value; + + // 迭代器所含成员数据 + value_pointer cur; // 指向所在缓冲区的当前元素 + value_pointer first; // 指向所在缓冲区的头部 + value_pointer last; // 指向所在缓冲区的尾部 + map_pointer node; // 缓冲区所在节点 + + // 构造、复制、移动函数 + deque_iterator() noexcept + : cur(nullptr), first(nullptr), last(nullptr), node(nullptr) { + } - deque_iterator(const iterator &rhs) - : cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) { - } - deque_iterator(iterator &&rhs) noexcept - : cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) { - rhs.cur = nullptr; - rhs.first = nullptr; - rhs.last = nullptr; - rhs.node = nullptr; - } + deque_iterator(value_pointer v, map_pointer n) + : cur(v), first(*n), last(*n + buffer_size), node(n) { + } - deque_iterator(const const_iterator &rhs) - : cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) { - } + deque_iterator(const iterator& rhs) + : cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) { + } - self &operator=(const iterator &rhs) { - if (this != &rhs) { - cur = rhs.cur; - first = rhs.first; - last = rhs.last; - node = rhs.node; - } - return *this; - } + deque_iterator(iterator&& rhs) noexcept + : cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) { + rhs.cur = nullptr; + rhs.first = nullptr; + rhs.last = nullptr; + rhs.node = nullptr; + } - // 转到另一个缓冲区 - void set_node(map_pointer new_node) { - node = new_node; - first = *new_node; - last = first + buffer_size; - } + deque_iterator(const const_iterator& rhs) + : cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) { + } - // 重载运算符 - reference operator*() const { - return *cur; - } - pointer operator->() const { - return cur; + self& operator=(const iterator& rhs) { + if (this != &rhs) { + cur = rhs.cur; + first = rhs.first; + last = rhs.last; + node = rhs.node; } + return *this; + } - difference_type operator-(const self &x) const { - return static_cast(buffer_size) * (node - x.node) + - (cur - first) - (x.cur - x.first); - } + // 转到另一个缓冲区 + void set_node(map_pointer new_node) { + node = new_node; + first = *new_node; + last = first + buffer_size; + } - self &operator++() { - ++cur; - if (cur == last) { // 如果到达缓冲区的尾 - set_node(node + 1); - cur = first; - } - return *this; - } - self operator++(int) { - self tmp = *this; - ++*this; - return tmp; - } + // 重载运算符 + reference operator*() const { + return *cur; + } - self &operator--() { - if (cur == first) { // 如果到达缓冲区的头 - set_node(node - 1); - cur = last; - } - --cur; - return *this; - } - self operator--(int) { - self tmp = *this; - --*this; - return tmp; - } + pointer operator->() const { + return cur; + } - self &operator+=(difference_type n) { - const auto offset = n + (cur - first); - if (offset >= 0 && offset < static_cast( - buffer_size)) { // 仍在当前缓冲区 - cur += n; - } - else { // 要跳到其他的缓冲区 - const auto node_offset = - offset > 0 - ? offset / static_cast(buffer_size) - : -static_cast((-offset - 1) / - buffer_size) - - 1; - set_node(node + node_offset); - cur = first + - (offset - - node_offset * static_cast(buffer_size)); - } - return *this; - } - self operator+(difference_type n) const { - self tmp = *this; - return tmp += n; - } - self &operator-=(difference_type n) { - return *this += -n; - } - self operator-(difference_type n) const { - self tmp = *this; - return tmp -= n; - } + difference_type operator-(const self& x) const { + return static_cast(buffer_size) * (node - x.node) + + (cur - first) - (x.cur - x.first); + } - reference operator[](difference_type n) const { - return *(*this + n); + self& operator++() { + ++cur; + if (cur == last) { // 如果到达缓冲区的尾 + set_node(node + 1); + cur = first; } + return *this; + } - // 重载比较操作符 - bool operator==(const self &rhs) const { - return cur == rhs.cur; - } - bool operator<(const self &rhs) const { - return node == rhs.node ? (cur < rhs.cur) : (node < rhs.node); - } - bool operator!=(const self &rhs) const { - return !(*this == rhs); - } - bool operator>(const self &rhs) const { - return rhs < *this; - } - bool operator<=(const self &rhs) const { - return !(rhs < *this); - } - bool operator>=(const self &rhs) const { - return !(*this < rhs); + self operator++(int) { + self tmp = *this; + ++*this; + return tmp; + } + + self& operator--() { + if (cur == first) { // 如果到达缓冲区的头 + set_node(node - 1); + cur = last; } - }; - - // 模板类 deque - // 模板参数代表数据类型 - template - class deque { - public: - // deque 的型别定义 - typedef mystl::allocator allocator_type; - typedef mystl::allocator data_allocator; - typedef mystl::allocator map_allocator; - - typedef typename allocator_type::value_type value_type; - typedef typename allocator_type::pointer pointer; - typedef typename allocator_type::const_pointer const_pointer; - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - typedef typename allocator_type::size_type size_type; - typedef typename allocator_type::difference_type difference_type; - typedef pointer * map_pointer; - typedef const_pointer * const_map_pointer; - - typedef deque_iterator iterator; - typedef deque_iterator const_iterator; - typedef mystl::reverse_iterator reverse_iterator; - typedef mystl::reverse_iterator const_reverse_iterator; - - allocator_type get_allocator() { - return allocator_type(); + --cur; + return *this; + } + + self operator--(int) { + self tmp = *this; + --*this; + return tmp; + } + + self& operator+=(difference_type n) { + const auto offset = n + (cur - first); + if (offset >= 0 + && offset < static_cast( + buffer_size)) { // 仍在当前缓冲区 + cur += n; + } + else { // 要跳到其他的缓冲区 + const auto node_offset + = offset > 0 + ? offset / static_cast(buffer_size) + : -static_cast((-offset - 1) / buffer_size) + - 1; + set_node(node + node_offset); + cur = first + + (offset + - node_offset * static_cast(buffer_size)); } + return *this; + } - static const size_type buffer_size = deque_buf_size::value; + self operator+(difference_type n) const { + self tmp = *this; + return tmp += n; + } - private: - // 用以下四个数据来表现一个 deque - iterator begin_; // 指向第一个节点 - iterator end_; // 指向最后一个结点 - map_pointer - map_; // 指向一块 map,map 中的每个元素都是一个指针,指向一个缓冲区 - size_type map_size_; // map 内指针的数目 + self& operator-=(difference_type n) { + return *this += -n; + } - public: - // 构造、复制、移动、析构函数 + self operator-(difference_type n) const { + self tmp = *this; + return tmp -= n; + } - deque() { - fill_init(0, value_type()); - } + reference operator[](difference_type n) const { + return *(*this + n); + } - explicit deque(size_type n) { - fill_init(n, value_type()); - } + // 重载比较操作符 + bool operator==(const self& rhs) const { + return cur == rhs.cur; + } - deque(size_type n, const value_type &value) { - fill_init(n, value); - } + bool operator<(const self& rhs) const { + return node == rhs.node ? (cur < rhs.cur) : (node < rhs.node); + } - template ::value, int>::type = 0> - deque(IIter first, IIter last) { - copy_init(first, last, iterator_category(first)); - } + bool operator!=(const self& rhs) const { + return !(*this == rhs); + } - deque(std::initializer_list ilist) { - copy_init(ilist.begin(), ilist.end(), - mystl::forward_iterator_tag()); - } + bool operator>(const self& rhs) const { + return rhs < *this; + } - deque(const deque &rhs) { - copy_init(rhs.begin(), rhs.end(), mystl::forward_iterator_tag()); - } - deque(deque &&rhs) noexcept - : begin_(mystl::move(rhs.begin_)), end_(mystl::move(rhs.end_)), - map_(rhs.map_), map_size_(rhs.map_size_) { - rhs.map_ = nullptr; - rhs.map_size_ = 0; - } + bool operator<=(const self& rhs) const { + return !(rhs < *this); + } - deque &operator=(const deque &rhs); - deque &operator=(deque &&rhs); + bool operator>=(const self& rhs) const { + return !(*this < rhs); + } +}; - deque &operator=(std::initializer_list ilist) { - deque tmp(ilist); - swap(tmp); - return *this; - } +// 模板类 deque +// 模板参数代表数据类型 +template +class deque { +public: + // deque 的型别定义 + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator map_allocator; + + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + typedef pointer* map_pointer; + typedef const_pointer* const_map_pointer; + + typedef deque_iterator iterator; + typedef deque_iterator const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + allocator_type get_allocator() { + return allocator_type(); + } - ~deque() { - if (map_ != nullptr) { - clear(); - data_allocator::deallocate(*begin_.node, buffer_size); - *begin_.node = nullptr; - map_allocator::deallocate(map_, map_size_); - map_ = nullptr; - } - } + static const size_type buffer_size = deque_buf_size::value; - public: - // 迭代器相关操作 +private: + // 用以下四个数据来表现一个 deque + iterator begin_; // 指向第一个节点 + iterator end_; // 指向最后一个结点 + map_pointer + map_; // 指向一块 map,map 中的每个元素都是一个指针,指向一个缓冲区 + size_type map_size_; // map 内指针的数目 - iterator begin() noexcept { - return begin_; - } - const_iterator begin() const noexcept { - return begin_; - } - iterator end() noexcept { - return end_; - } - const_iterator end() const noexcept { - return end_; - } +public: + // 构造、复制、移动、析构函数 - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return reverse_iterator(begin()); - } + deque() { + fill_init(0, value_type()); + } - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } + explicit deque(size_type n) { + fill_init(n, value_type()); + } - // 容量相关操作 + deque(size_type n, const value_type& value) { + fill_init(n, value); + } - bool empty() const noexcept { - return begin() == end(); - } - size_type size() const noexcept { - return end_ - begin_; - } - size_type max_size() const noexcept { - return static_cast(-1); - } - void resize(size_type new_size) { - resize(new_size, value_type()); - } - void resize(size_type new_size, const value_type &value); - void shrink_to_fit() noexcept; + template ::value, int>::type + = 0> + deque(IIter first, IIter last) { + copy_init(first, last, iterator_category(first)); + } - // 访问元素相关操作 - reference operator[](size_type n) { - MYSTL_DEBUG(n < size()); - return begin_[n]; - } - const_reference operator[](size_type n) const { - MYSTL_DEBUG(n < size()); - return begin_[n]; - } + deque(std::initializer_list ilist) { + copy_init(ilist.begin(), ilist.end(), mystl::forward_iterator_tag()); + } - reference at(size_type n) { - THROW_OUT_OF_RANGE_IF(!(n < size()), - "deque::at() subscript out of range"); - return (*this)[n]; - } - const_reference at(size_type n) const { - THROW_OUT_OF_RANGE_IF(!(n < size()), - "deque::at() subscript out of range"); - return (*this)[n]; - } + deque(const deque& rhs) { + copy_init(rhs.begin(), rhs.end(), mystl::forward_iterator_tag()); + } - reference front() { - MYSTL_DEBUG(!empty()); - return *begin(); - } - const_reference front() const { - MYSTL_DEBUG(!empty()); - return *begin(); - } - reference back() { - MYSTL_DEBUG(!empty()); - return *(end() - 1); - } - const_reference back() const { - MYSTL_DEBUG(!empty()); - return *(end() - 1); - } + deque(deque&& rhs) noexcept + : begin_(mystl::move(rhs.begin_)), + end_(mystl::move(rhs.end_)), + map_(rhs.map_), + map_size_(rhs.map_size_) { + rhs.map_ = nullptr; + rhs.map_size_ = 0; + } - // 修改容器相关操作 + deque& operator=(const deque& rhs); + deque& operator=(deque&& rhs); - // assign + deque& operator=(std::initializer_list ilist) { + deque tmp(ilist); + swap(tmp); + return *this; + } - void assign(size_type n, const value_type &value) { - fill_assign(n, value); + ~deque() { + if (map_ != nullptr) { + clear(); + data_allocator::deallocate(*begin_.node, buffer_size); + *begin_.node = nullptr; + map_allocator::deallocate(map_, map_size_); + map_ = nullptr; } + } - template ::value, int>::type = 0> - void assign(IIter first, IIter last) { - copy_assign(first, last, iterator_category(first)); - } +public: + // 迭代器相关操作 - void assign(std::initializer_list ilist) { - copy_assign(ilist.begin(), ilist.end(), - mystl::forward_iterator_tag{}); - } + iterator begin() noexcept { + return begin_; + } - // emplace_front / emplace_back / emplace + const_iterator begin() const noexcept { + return begin_; + } - template - void emplace_front(Args &&...args); - template - void emplace_back(Args &&...args); - template - iterator emplace(iterator pos, Args &&...args); + iterator end() noexcept { + return end_; + } - // push_front / push_back + const_iterator end() const noexcept { + return end_; + } - void push_front(const value_type &value); - void push_back(const value_type &value); + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } - void push_front(value_type &&value) { - emplace_front(mystl::move(value)); - } - void push_back(value_type &&value) { - emplace_back(mystl::move(value)); - } + const_reverse_iterator rbegin() const noexcept { + return reverse_iterator(end()); + } - // pop_back / pop_front + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - void pop_front(); - void pop_back(); + const_reverse_iterator rend() const noexcept { + return reverse_iterator(begin()); + } - // insert + const_iterator cbegin() const noexcept { + return begin(); + } - iterator insert(iterator position, const value_type &value); - iterator insert(iterator position, value_type &&value); - void insert(iterator position, size_type n, const value_type &value); - template ::value, int>::type = 0> - void insert(iterator position, IIter first, IIter last) { - insert_dispatch(position, first, last, iterator_category(first)); - } + const_iterator cend() const noexcept { + return end(); + } - // erase /clear - - iterator erase(iterator position); - iterator erase(iterator first, iterator last); - void clear(); - - // swap - - void swap(deque &rhs) noexcept; - - private: - // helper functions - - // create node / destroy node - map_pointer create_map(size_type size); - void create_buffer(map_pointer nstart, map_pointer nfinish); - void destroy_buffer(map_pointer nstart, map_pointer nfinish); - - // initialize - void map_init(size_type nelem); - void fill_init(size_type n, const value_type &value); - template - void copy_init(IIter, IIter, input_iterator_tag); - template - void copy_init(FIter, FIter, forward_iterator_tag); - - // assign - void fill_assign(size_type n, const value_type &value); - template - void copy_assign(IIter first, IIter last, input_iterator_tag); - template - void copy_assign(FIter first, FIter last, forward_iterator_tag); - - // insert - template - iterator insert_aux(iterator position, Args &&...args); - void fill_insert(iterator position, size_type n, const value_type &x); - template - void copy_insert(iterator, FIter, FIter, size_type); - template - void insert_dispatch(iterator, IIter, IIter, input_iterator_tag); - template - void insert_dispatch(iterator, FIter, FIter, forward_iterator_tag); - - // reallocate - void require_capacity(size_type n, bool front); - void reallocate_map_at_front(size_type need); - void reallocate_map_at_back(size_type need); - }; - - /*****************************************************************************************/ - - // 复制赋值运算符 - template - deque &deque::operator=(const deque &rhs) { - if (this != &rhs) { - const auto len = size(); - if (len >= rhs.size()) { - erase(mystl::copy(rhs.begin_, rhs.end_, begin_), end_); - } - else { - iterator mid = rhs.begin() + static_cast(len); - mystl::copy(rhs.begin_, mid, begin_); - insert(end_, mid, rhs.end_); - } - } - return *this; + const_reverse_iterator crbegin() const noexcept { + return rbegin(); } - // 移动赋值运算符 - template - deque &deque::operator=(deque &&rhs) { - clear(); - begin_ = mystl::move(rhs.begin_); - end_ = mystl::move(rhs.end_); - map_ = rhs.map_; - map_size_ = rhs.map_size_; - rhs.map_ = nullptr; - rhs.map_size_ = 0; - return *this; + const_reverse_iterator crend() const noexcept { + return rend(); } - // 重置容器大小 - template - void deque::resize(size_type new_size, const value_type &value) { - const auto len = size(); - if (new_size < len) { - erase(begin_ + new_size, end_); - } - else { - insert(end_, new_size - len, value); - } + // 容量相关操作 + + bool empty() const noexcept { + return begin() == end(); } - // 减小容器容量 - template - void deque::shrink_to_fit() noexcept { - // 至少会留下头部缓冲区 - for (auto cur = map_; cur < begin_.node; ++cur) { - data_allocator::deallocate(*cur, buffer_size); - *cur = nullptr; - } - for (auto cur = end_.node + 1; cur < map_ + map_size_; ++cur) { - data_allocator::deallocate(*cur, buffer_size); - *cur = nullptr; - } + size_type size() const noexcept { + return end_ - begin_; } - // 在头部就地构建元素 - template - template - void deque::emplace_front(Args &&...args) { - if (begin_.cur != begin_.first) { - data_allocator::construct(begin_.cur - 1, - mystl::forward(args)...); - --begin_.cur; - } - else { - require_capacity(1, true); - try { - --begin_; - data_allocator::construct(begin_.cur, - mystl::forward(args)...); - } catch (...) { - ++begin_; - throw; - } - } + size_type max_size() const noexcept { + return static_cast(-1); } - // 在尾部就地构建元素 - template - template - void deque::emplace_back(Args &&...args) { - if (end_.cur != end_.last - 1) { - data_allocator::construct(end_.cur, mystl::forward(args)...); - ++end_.cur; - } - else { - require_capacity(1, false); - data_allocator::construct(end_.cur, mystl::forward(args)...); - ++end_; - } + void resize(size_type new_size) { + resize(new_size, value_type()); } - // 在 pos 位置就地构建元素 - template - template - typename deque::iterator deque::emplace(iterator pos, - Args &&...args) { - if (pos.cur == begin_.cur) { - emplace_front(mystl::forward(args)...); - return begin_; - } - else if (pos.cur == end_.cur) { - emplace_back(mystl::forward(args)...); - return end_ - 1; - } - return insert_aux(pos, mystl::forward(args)...); + void resize(size_type new_size, const value_type& value); + void shrink_to_fit() noexcept; + + // 访问元素相关操作 + reference operator[](size_type n) { + MYSTL_DEBUG(n < size()); + return begin_[n]; } - // 在头部插入元素 - template - void deque::push_front(const value_type &value) { - if (begin_.cur != begin_.first) { - data_allocator::construct(begin_.cur - 1, value); - --begin_.cur; - } - else { - require_capacity(1, true); - try { - --begin_; - data_allocator::construct(begin_.cur, value); - } catch (...) { - ++begin_; - throw; - } - } + const_reference operator[](size_type n) const { + MYSTL_DEBUG(n < size()); + return begin_[n]; } - // 在尾部插入元素 - template - void deque::push_back(const value_type &value) { - if (end_.cur != end_.last - 1) { - data_allocator::construct(end_.cur, value); - ++end_.cur; - } - else { - require_capacity(1, false); - data_allocator::construct(end_.cur, value); - ++end_; - } + reference at(size_type n) { + THROW_OUT_OF_RANGE_IF(!(n < size()), + "deque::at() subscript out of range"); + return (*this)[n]; } - // 弹出头部元素 - template - void deque::pop_front() { + const_reference at(size_type n) const { + THROW_OUT_OF_RANGE_IF(!(n < size()), + "deque::at() subscript out of range"); + return (*this)[n]; + } + + reference front() { MYSTL_DEBUG(!empty()); - if (begin_.cur != begin_.last - 1) { - data_allocator::destroy(begin_.cur); - ++begin_.cur; - } - else { - data_allocator::destroy(begin_.cur); - ++begin_; - destroy_buffer(begin_.node - 1, begin_.node - 1); - } + return *begin(); } - // 弹出尾部元素 - template - void deque::pop_back() { + const_reference front() const { MYSTL_DEBUG(!empty()); - if (end_.cur != end_.first) { - --end_.cur; - data_allocator::destroy(end_.cur); - } - else { - --end_; - data_allocator::destroy(end_.cur); - destroy_buffer(end_.node + 1, end_.node + 1); - } + return *begin(); } - // 在 position 处插入元素 - template - typename deque::iterator deque::insert(iterator position, - const value_type &value) { - if (position.cur == begin_.cur) { - push_front(value); - return begin_; - } - else if (position.cur == end_.cur) { - push_back(value); - auto tmp = end_; - --tmp; - return tmp; - } - else { - return insert_aux(position, value); - } + reference back() { + MYSTL_DEBUG(!empty()); + return *(end() - 1); } - template - typename deque::iterator deque::insert(iterator position, - value_type &&value) { - if (position.cur == begin_.cur) { - emplace_front(mystl::move(value)); - return begin_; - } - else if (position.cur == end_.cur) { - emplace_back(mystl::move(value)); - auto tmp = end_; - --tmp; - return tmp; - } - else { - return insert_aux(position, mystl::move(value)); - } + const_reference back() const { + MYSTL_DEBUG(!empty()); + return *(end() - 1); } - // 在 position 位置插入 n 个元素 - template - void deque::insert(iterator position, size_type n, - const value_type &value) { - if (position.cur == begin_.cur) { - require_capacity(n, true); - auto new_begin = begin_ - n; - mystl::uninitialized_fill_n(new_begin, n, value); - begin_ = new_begin; - } - else if (position.cur == end_.cur) { - require_capacity(n, false); - auto new_end = end_ + n; - mystl::uninitialized_fill_n(end_, n, value); - end_ = new_end; - } - else { - fill_insert(position, n, value); - } + // 修改容器相关操作 + + // assign + + void assign(size_type n, const value_type& value) { + fill_assign(n, value); } - // 删除 position 处的元素 - template - typename deque::iterator deque::erase(iterator position) { - auto next = position; - ++next; - const size_type elems_before = position - begin_; - if (elems_before < (size() / 2)) { - mystl::copy_backward(begin_, position, next); - pop_front(); - } - else { - mystl::copy(next, end_, position); - pop_back(); - } - return begin_ + elems_before; + template ::value, int>::type + = 0> + void assign(IIter first, IIter last) { + copy_assign(first, last, iterator_category(first)); } - // 删除[first, last)上的元素 - template - typename deque::iterator deque::erase(iterator first, iterator last) { - if (first == begin_ && last == end_) { - clear(); - return end_; - } - else { - const size_type len = last - first; - const size_type elems_before = first - begin_; - if (elems_before < ((size() - len) / 2)) { - mystl::copy_backward(begin_, first, last); - auto new_begin = begin_ + len; - data_allocator::destroy(begin_.cur, new_begin.cur); - begin_ = new_begin; - } - else { - mystl::copy(last, end_, first); - auto new_end = end_ - len; - data_allocator::destroy(new_end.cur, end_.cur); - end_ = new_end; - } - return begin_ + elems_before; - } + void assign(std::initializer_list ilist) { + copy_assign(ilist.begin(), ilist.end(), mystl::forward_iterator_tag {}); } - // 清空 deque - template - void deque::clear() { - // clear 会保留头部的缓冲区 - for (map_pointer cur = begin_.node + 1; cur < end_.node; ++cur) { - data_allocator::destroy(*cur, *cur + buffer_size); - } - if (begin_.node != end_.node) { // 有两个以上的缓冲区 - mystl::destroy(begin_.cur, begin_.last); - mystl::destroy(end_.first, end_.cur); - } - else { - mystl::destroy(begin_.cur, end_.cur); - } - shrink_to_fit(); - end_ = begin_; + // emplace_front / emplace_back / emplace + + template + void emplace_front(Args&&... args); + template + void emplace_back(Args&&... args); + template + iterator emplace(iterator pos, Args&&... args); + + // push_front / push_back + + void push_front(const value_type& value); + void push_back(const value_type& value); + + void push_front(value_type&& value) { + emplace_front(mystl::move(value)); } - // 交换两个 deque - template - void deque::swap(deque &rhs) noexcept { - if (this != &rhs) { - mystl::swap(begin_, rhs.begin_); - mystl::swap(end_, rhs.end_); - mystl::swap(map_, rhs.map_); - mystl::swap(map_size_, rhs.map_size_); - } + void push_back(value_type&& value) { + emplace_back(mystl::move(value)); } - /*****************************************************************************************/ - // helper function + // pop_back / pop_front - template - typename deque::map_pointer deque::create_map(size_type size) { - map_pointer mp = nullptr; - mp = map_allocator::allocate(size); - for (size_type i = 0; i < size; ++i) - *(mp + i) = nullptr; - return mp; - } + void pop_front(); + void pop_back(); - // create_buffer 函数 - template - void deque::create_buffer(map_pointer nstart, map_pointer nfinish) { - map_pointer cur; - try { - for (cur = nstart; cur <= nfinish; ++cur) { - *cur = data_allocator::allocate(buffer_size); - } - } catch (...) { - while (cur != nstart) { - --cur; - data_allocator::deallocate(*cur, buffer_size); - *cur = nullptr; - } - throw; - } + // insert + + iterator insert(iterator position, const value_type& value); + iterator insert(iterator position, value_type&& value); + void insert(iterator position, size_type n, const value_type& value); + + template ::value, int>::type + = 0> + void insert(iterator position, IIter first, IIter last) { + insert_dispatch(position, first, last, iterator_category(first)); } - // destroy_buffer 函数 - template - void deque::destroy_buffer(map_pointer nstart, map_pointer nfinish) { - for (map_pointer n = nstart; n <= nfinish; ++n) { - data_allocator::deallocate(*n, buffer_size); - *n = nullptr; + // erase /clear + + iterator erase(iterator position); + iterator erase(iterator first, iterator last); + void clear(); + + // swap + + void swap(deque& rhs) noexcept; + +private: + // helper functions + + // create node / destroy node + map_pointer create_map(size_type size); + void create_buffer(map_pointer nstart, map_pointer nfinish); + void destroy_buffer(map_pointer nstart, map_pointer nfinish); + + // initialize + void map_init(size_type nelem); + void fill_init(size_type n, const value_type& value); + template + void copy_init(IIter, IIter, input_iterator_tag); + template + void copy_init(FIter, FIter, forward_iterator_tag); + + // assign + void fill_assign(size_type n, const value_type& value); + template + void copy_assign(IIter first, IIter last, input_iterator_tag); + template + void copy_assign(FIter first, FIter last, forward_iterator_tag); + + // insert + template + iterator insert_aux(iterator position, Args&&... args); + void fill_insert(iterator position, size_type n, const value_type& x); + template + void copy_insert(iterator, FIter, FIter, size_type); + template + void insert_dispatch(iterator, IIter, IIter, input_iterator_tag); + template + void insert_dispatch(iterator, FIter, FIter, forward_iterator_tag); + + // reallocate + void require_capacity(size_type n, bool front); + void reallocate_map_at_front(size_type need); + void reallocate_map_at_back(size_type need); +}; + +/*****************************************************************************************/ + +// 复制赋值运算符 +template +deque& deque::operator=(const deque& rhs) { + if (this != &rhs) { + const auto len = size(); + if (len >= rhs.size()) { + erase(mystl::copy(rhs.begin_, rhs.end_, begin_), end_); + } + else { + iterator mid = rhs.begin() + static_cast(len); + mystl::copy(rhs.begin_, mid, begin_); + insert(end_, mid, rhs.end_); } } - - // map_init 函数 - template - void deque::map_init(size_type nElem) { - const size_type nNode = nElem / buffer_size + 1; // 需要分配的缓冲区个数 - map_size_ = - mystl::max(static_cast(DEQUE_MAP_INIT_SIZE), nNode + 2); + return *this; +} + +// 移动赋值运算符 +template +deque& deque::operator=(deque&& rhs) { + clear(); + begin_ = mystl::move(rhs.begin_); + end_ = mystl::move(rhs.end_); + map_ = rhs.map_; + map_size_ = rhs.map_size_; + rhs.map_ = nullptr; + rhs.map_size_ = 0; + return *this; +} + +// 重置容器大小 +template +void deque::resize(size_type new_size, const value_type& value) { + const auto len = size(); + if (new_size < len) { + erase(begin_ + new_size, end_); + } + else { + insert(end_, new_size - len, value); + } +} + +// 减小容器容量 +template +void deque::shrink_to_fit() noexcept { + // 至少会留下头部缓冲区 + for (auto cur = map_; cur < begin_.node; ++cur) { + data_allocator::deallocate(*cur, buffer_size); + *cur = nullptr; + } + for (auto cur = end_.node + 1; cur < map_ + map_size_; ++cur) { + data_allocator::deallocate(*cur, buffer_size); + *cur = nullptr; + } +} + +// 在头部就地构建元素 +template +template +void deque::emplace_front(Args&&... args) { + if (begin_.cur != begin_.first) { + data_allocator::construct(begin_.cur - 1, + mystl::forward(args)...); + --begin_.cur; + } + else { + require_capacity(1, true); try { - map_ = create_map(map_size_); + --begin_; + data_allocator::construct(begin_.cur, + mystl::forward(args)...); } catch (...) { - map_ = nullptr; - map_size_ = 0; + ++begin_; throw; } - - // 让 nstart 和 nfinish 都指向 map_ 最中央的区域,方便向头尾扩充 - map_pointer nstart = map_ + (map_size_ - nNode) / 2; - map_pointer nfinish = nstart + nNode - 1; + } +} + +// 在尾部就地构建元素 +template +template +void deque::emplace_back(Args&&... args) { + if (end_.cur != end_.last - 1) { + data_allocator::construct(end_.cur, mystl::forward(args)...); + ++end_.cur; + } + else { + require_capacity(1, false); + data_allocator::construct(end_.cur, mystl::forward(args)...); + ++end_; + } +} + +// 在 pos 位置就地构建元素 +template +template +typename deque::iterator deque::emplace(iterator pos, Args&&... args) { + if (pos.cur == begin_.cur) { + emplace_front(mystl::forward(args)...); + return begin_; + } + else if (pos.cur == end_.cur) { + emplace_back(mystl::forward(args)...); + return end_ - 1; + } + return insert_aux(pos, mystl::forward(args)...); +} + +// 在头部插入元素 +template +void deque::push_front(const value_type& value) { + if (begin_.cur != begin_.first) { + data_allocator::construct(begin_.cur - 1, value); + --begin_.cur; + } + else { + require_capacity(1, true); try { - create_buffer(nstart, nfinish); + --begin_; + data_allocator::construct(begin_.cur, value); } catch (...) { - map_allocator::deallocate(map_, map_size_); - map_ = nullptr; - map_size_ = 0; + ++begin_; throw; } - begin_.set_node(nstart); - end_.set_node(nfinish); - begin_.cur = begin_.first; - end_.cur = end_.first + (nElem % buffer_size); - } - - // fill_init 函数 - template - void deque::fill_init(size_type n, const value_type &value) { - map_init(n); - if (n != 0) { - for (auto cur = begin_.node; cur < end_.node; ++cur) { - mystl::uninitialized_fill(*cur, *cur + buffer_size, value); - } - mystl::uninitialized_fill(end_.first, end_.cur, value); - } } - - // copy_init 函数 - template - template - void deque::copy_init(IIter first, IIter last, input_iterator_tag) { - const size_type n = mystl::distance(first, last); - map_init(n); - for (; first != last; ++first) - emplace_back(*first); +} + +// 在尾部插入元素 +template +void deque::push_back(const value_type& value) { + if (end_.cur != end_.last - 1) { + data_allocator::construct(end_.cur, value); + ++end_.cur; } - - template - template - void deque::copy_init(FIter first, FIter last, forward_iterator_tag) { - const size_type n = mystl::distance(first, last); - map_init(n); - for (auto cur = begin_.node; cur < end_.node; ++cur) { - auto next = first; - mystl::advance(next, buffer_size); - mystl::uninitialized_copy(first, next, *cur); - first = next; - } - mystl::uninitialized_copy(first, last, end_.first); + else { + require_capacity(1, false); + data_allocator::construct(end_.cur, value); + ++end_; } - - // fill_assign 函数 - template - void deque::fill_assign(size_type n, const value_type &value) { - if (n > size()) { - mystl::fill(begin(), end(), value); - insert(end(), n - size(), value); - } - else { - erase(begin() + n, end()); - mystl::fill(begin(), end(), value); - } +} + +// 弹出头部元素 +template +void deque::pop_front() { + MYSTL_DEBUG(!empty()); + if (begin_.cur != begin_.last - 1) { + data_allocator::destroy(begin_.cur); + ++begin_.cur; + } + else { + data_allocator::destroy(begin_.cur); + ++begin_; + destroy_buffer(begin_.node - 1, begin_.node - 1); + } +} + +// 弹出尾部元素 +template +void deque::pop_back() { + MYSTL_DEBUG(!empty()); + if (end_.cur != end_.first) { + --end_.cur; + data_allocator::destroy(end_.cur); + } + else { + --end_; + data_allocator::destroy(end_.cur); + destroy_buffer(end_.node + 1, end_.node + 1); + } +} + +// 在 position 处插入元素 +template +typename deque::iterator +deque::insert(iterator position, const value_type& value) { + if (position.cur == begin_.cur) { + push_front(value); + return begin_; + } + else if (position.cur == end_.cur) { + push_back(value); + auto tmp = end_; + --tmp; + return tmp; + } + else { + return insert_aux(position, value); } +} + +template +typename deque::iterator +deque::insert(iterator position, value_type&& value) { + if (position.cur == begin_.cur) { + emplace_front(mystl::move(value)); + return begin_; + } + else if (position.cur == end_.cur) { + emplace_back(mystl::move(value)); + auto tmp = end_; + --tmp; + return tmp; + } + else { + return insert_aux(position, mystl::move(value)); + } +} + +// 在 position 位置插入 n 个元素 +template +void deque::insert(iterator position, size_type n, const value_type& value) { + if (position.cur == begin_.cur) { + require_capacity(n, true); + auto new_begin = begin_ - n; + mystl::uninitialized_fill_n(new_begin, n, value); + begin_ = new_begin; + } + else if (position.cur == end_.cur) { + require_capacity(n, false); + auto new_end = end_ + n; + mystl::uninitialized_fill_n(end_, n, value); + end_ = new_end; + } + else { + fill_insert(position, n, value); + } +} + +// 删除 position 处的元素 +template +typename deque::iterator deque::erase(iterator position) { + auto next = position; + ++next; + const size_type elems_before = position - begin_; + if (elems_before < (size() / 2)) { + mystl::copy_backward(begin_, position, next); + pop_front(); + } + else { + mystl::copy(next, end_, position); + pop_back(); + } + return begin_ + elems_before; +} - // copy_assign 函数 - template - template - void deque::copy_assign(IIter first, IIter last, input_iterator_tag) { - auto first1 = begin(); - auto last1 = end(); - for (; first != last && first1 != last1; ++first, ++first1) { - *first1 = *first; - } - if (first1 != last1) { - erase(first1, last1); +// 删除[first, last)上的元素 +template +typename deque::iterator deque::erase(iterator first, iterator last) { + if (first == begin_ && last == end_) { + clear(); + return end_; + } + else { + const size_type len = last - first; + const size_type elems_before = first - begin_; + if (elems_before < ((size() - len) / 2)) { + mystl::copy_backward(begin_, first, last); + auto new_begin = begin_ + len; + data_allocator::destroy(begin_.cur, new_begin.cur); + begin_ = new_begin; } else { - insert_dispatch(end_, first, last, input_iterator_tag{}); + mystl::copy(last, end_, first); + auto new_end = end_ - len; + data_allocator::destroy(new_end.cur, end_.cur); + end_ = new_end; } + return begin_ + elems_before; + } +} + +// 清空 deque +template +void deque::clear() { + // clear 会保留头部的缓冲区 + for (map_pointer cur = begin_.node + 1; cur < end_.node; ++cur) { + data_allocator::destroy(*cur, *cur + buffer_size); + } + if (begin_.node != end_.node) { // 有两个以上的缓冲区 + mystl::destroy(begin_.cur, begin_.last); + mystl::destroy(end_.first, end_.cur); } + else { + mystl::destroy(begin_.cur, end_.cur); + } + shrink_to_fit(); + end_ = begin_; +} + +// 交换两个 deque +template +void deque::swap(deque& rhs) noexcept { + if (this != &rhs) { + mystl::swap(begin_, rhs.begin_); + mystl::swap(end_, rhs.end_); + mystl::swap(map_, rhs.map_); + mystl::swap(map_size_, rhs.map_size_); + } +} - template - template - void deque::copy_assign(FIter first, FIter last, forward_iterator_tag) { - const size_type len1 = size(); - const size_type len2 = mystl::distance(first, last); - if (len1 < len2) { - auto next = first; - mystl::advance(next, len1); - mystl::copy(first, next, begin_); - insert_dispatch(end_, next, last, forward_iterator_tag{}); - } - else { - erase(mystl::copy(first, last, begin_), end_); +/*****************************************************************************************/ +// helper function + +template +typename deque::map_pointer deque::create_map(size_type size) { + map_pointer mp = nullptr; + mp = map_allocator::allocate(size); + for (size_type i = 0; i < size; ++i) { + *(mp + i) = nullptr; + } + return mp; +} + +// create_buffer 函数 +template +void deque::create_buffer(map_pointer nstart, map_pointer nfinish) { + map_pointer cur; + try { + for (cur = nstart; cur <= nfinish; ++cur) { + *cur = data_allocator::allocate(buffer_size); + } + } catch (...) { + while (cur != nstart) { + --cur; + data_allocator::deallocate(*cur, buffer_size); + *cur = nullptr; } + throw; + } +} + +// destroy_buffer 函数 +template +void deque::destroy_buffer(map_pointer nstart, map_pointer nfinish) { + for (map_pointer n = nstart; n <= nfinish; ++n) { + data_allocator::deallocate(*n, buffer_size); + *n = nullptr; + } +} + +// map_init 函数 +template +void deque::map_init(size_type nElem) { + const size_type nNode = nElem / buffer_size + 1; // 需要分配的缓冲区个数 + map_size_ + = mystl::max(static_cast(DEQUE_MAP_INIT_SIZE), nNode + 2); + try { + map_ = create_map(map_size_); + } catch (...) { + map_ = nullptr; + map_size_ = 0; + throw; } - // insert_aux 函数 - template - template - typename deque::iterator deque::insert_aux(iterator position, - Args &&...args) { - const size_type elems_before = position - begin_; - value_type value_copy = value_type(mystl::forward(args)...); - if (elems_before < (size() / 2)) { // 在前半段插入 - emplace_front(front()); - auto front1 = begin_; - ++front1; - auto front2 = front1; - ++front2; - position = begin_ + elems_before; - auto pos = position; - ++pos; - mystl::copy(front2, pos, front1); - } - else { // 在后半段插入 - emplace_back(back()); - auto back1 = end_; - --back1; - auto back2 = back1; - --back2; - position = begin_ + elems_before; - mystl::copy_backward(position, back2, back1); + // 让 nstart 和 nfinish 都指向 map_ 最中央的区域,方便向头尾扩充 + map_pointer nstart = map_ + (map_size_ - nNode) / 2; + map_pointer nfinish = nstart + nNode - 1; + try { + create_buffer(nstart, nfinish); + } catch (...) { + map_allocator::deallocate(map_, map_size_); + map_ = nullptr; + map_size_ = 0; + throw; + } + begin_.set_node(nstart); + end_.set_node(nfinish); + begin_.cur = begin_.first; + end_.cur = end_.first + (nElem % buffer_size); +} + +// fill_init 函数 +template +void deque::fill_init(size_type n, const value_type& value) { + map_init(n); + if (n != 0) { + for (auto cur = begin_.node; cur < end_.node; ++cur) { + mystl::uninitialized_fill(*cur, *cur + buffer_size, value); } - *position = mystl::move(value_copy); - return position; - } - - // fill_insert 函数 - template - void deque::fill_insert(iterator position, size_type n, - const value_type &value) { - const size_type elems_before = position - begin_; - const size_type len = size(); - auto value_copy = value; - if (elems_before < (len / 2)) { - require_capacity(n, true); - // 原来的迭代器可能会失效 - auto old_begin = begin_; - auto new_begin = begin_ - n; - position = begin_ + elems_before; - try { - if (elems_before >= n) { - auto begin_n = begin_ + n; - mystl::uninitialized_copy(begin_, begin_n, new_begin); - begin_ = new_begin; - mystl::copy(begin_n, position, old_begin); - mystl::fill(position - n, position, value_copy); - } - else { - mystl::uninitialized_fill( - mystl::uninitialized_copy(begin_, position, new_begin), - begin_, value_copy); - begin_ = new_begin; - mystl::fill(old_begin, position, value_copy); - } - } catch (...) { - if (new_begin.node != begin_.node) - destroy_buffer(new_begin.node, begin_.node - 1); - throw; + mystl::uninitialized_fill(end_.first, end_.cur, value); + } +} + +// copy_init 函数 +template +template +void deque::copy_init(IIter first, IIter last, input_iterator_tag) { + const size_type n = mystl::distance(first, last); + map_init(n); + for (; first != last; ++first) { + emplace_back(*first); + } +} + +template +template +void deque::copy_init(FIter first, FIter last, forward_iterator_tag) { + const size_type n = mystl::distance(first, last); + map_init(n); + for (auto cur = begin_.node; cur < end_.node; ++cur) { + auto next = first; + mystl::advance(next, buffer_size); + mystl::uninitialized_copy(first, next, *cur); + first = next; + } + mystl::uninitialized_copy(first, last, end_.first); +} + +// fill_assign 函数 +template +void deque::fill_assign(size_type n, const value_type& value) { + if (n > size()) { + mystl::fill(begin(), end(), value); + insert(end(), n - size(), value); + } + else { + erase(begin() + n, end()); + mystl::fill(begin(), end(), value); + } +} + +// copy_assign 函数 +template +template +void deque::copy_assign(IIter first, IIter last, input_iterator_tag) { + auto first1 = begin(); + auto last1 = end(); + for (; first != last && first1 != last1; ++first, ++first1) { + *first1 = *first; + } + if (first1 != last1) { + erase(first1, last1); + } + else { + insert_dispatch(end_, first, last, input_iterator_tag {}); + } +} + +template +template +void deque::copy_assign(FIter first, FIter last, forward_iterator_tag) { + const size_type len1 = size(); + const size_type len2 = mystl::distance(first, last); + if (len1 < len2) { + auto next = first; + mystl::advance(next, len1); + mystl::copy(first, next, begin_); + insert_dispatch(end_, next, last, forward_iterator_tag {}); + } + else { + erase(mystl::copy(first, last, begin_), end_); + } +} + +// insert_aux 函数 +template +template +typename deque::iterator +deque::insert_aux(iterator position, Args&&... args) { + const size_type elems_before = position - begin_; + value_type value_copy = value_type(mystl::forward(args)...); + if (elems_before < (size() / 2)) { // 在前半段插入 + emplace_front(front()); + auto front1 = begin_; + ++front1; + auto front2 = front1; + ++front2; + position = begin_ + elems_before; + auto pos = position; + ++pos; + mystl::copy(front2, pos, front1); + } + else { // 在后半段插入 + emplace_back(back()); + auto back1 = end_; + --back1; + auto back2 = back1; + --back2; + position = begin_ + elems_before; + mystl::copy_backward(position, back2, back1); + } + *position = mystl::move(value_copy); + return position; +} + +// fill_insert 函数 +template +void deque::fill_insert(iterator position, size_type n, + const value_type& value) { + const size_type elems_before = position - begin_; + const size_type len = size(); + auto value_copy = value; + if (elems_before < (len / 2)) { + require_capacity(n, true); + // 原来的迭代器可能会失效 + auto old_begin = begin_; + auto new_begin = begin_ - n; + position = begin_ + elems_before; + try { + if (elems_before >= n) { + auto begin_n = begin_ + n; + mystl::uninitialized_copy(begin_, begin_n, new_begin); + begin_ = new_begin; + mystl::copy(begin_n, position, old_begin); + mystl::fill(position - n, position, value_copy); } - } - else { - require_capacity(n, false); - // 原来的迭代器可能会失效 - auto old_end = end_; - auto new_end = end_ + n; - const size_type elems_after = len - elems_before; - position = end_ - elems_after; - try { - if (elems_after > n) { - auto end_n = end_ - n; - mystl::uninitialized_copy(end_n, end_, end_); - end_ = new_end; - mystl::copy_backward(position, end_n, old_end); - mystl::fill(position, position + n, value_copy); - } - else { - mystl::uninitialized_fill(end_, position + n, value_copy); - mystl::uninitialized_copy(position, end_, position + n); - end_ = new_end; - mystl::fill(position, old_end, value_copy); - } - } catch (...) { - if (new_end.node != end_.node) - destroy_buffer(end_.node + 1, new_end.node); - throw; + else { + mystl::uninitialized_fill(mystl::uninitialized_copy(begin_, + position, + new_begin), + begin_, value_copy); + begin_ = new_begin; + mystl::fill(old_begin, position, value_copy); + } + } catch (...) { + if (new_begin.node != begin_.node) { + destroy_buffer(new_begin.node, begin_.node - 1); } + throw; } } - - // copy_insert - template - template - void deque::copy_insert(iterator position, FIter first, FIter last, - size_type n) { - const size_type elems_before = position - begin_; - auto len = size(); - if (elems_before < (len / 2)) { - require_capacity(n, true); - // 原来的迭代器可能会失效 - auto old_begin = begin_; - auto new_begin = begin_ - n; - position = begin_ + elems_before; - try { - if (elems_before >= n) { - auto begin_n = begin_ + n; - mystl::uninitialized_copy(begin_, begin_n, new_begin); - begin_ = new_begin; - mystl::copy(begin_n, position, old_begin); - mystl::copy(first, last, position - n); - } - else { - auto mid = first; - mystl::advance(mid, n - elems_before); - mystl::uninitialized_copy( - first, mid, - mystl::uninitialized_copy(begin_, position, new_begin)); - begin_ = new_begin; - mystl::copy(mid, last, old_begin); - } - } catch (...) { - if (new_begin.node != begin_.node) - destroy_buffer(new_begin.node, begin_.node - 1); - throw; + else { + require_capacity(n, false); + // 原来的迭代器可能会失效 + auto old_end = end_; + auto new_end = end_ + n; + const size_type elems_after = len - elems_before; + position = end_ - elems_after; + try { + if (elems_after > n) { + auto end_n = end_ - n; + mystl::uninitialized_copy(end_n, end_, end_); + end_ = new_end; + mystl::copy_backward(position, end_n, old_end); + mystl::fill(position, position + n, value_copy); } - } - else { - require_capacity(n, false); - // 原来的迭代器可能会失效 - auto old_end = end_; - auto new_end = end_ + n; - const auto elems_after = len - elems_before; - position = end_ - elems_after; - try { - if (elems_after > n) { - auto end_n = end_ - n; - mystl::uninitialized_copy(end_n, end_, end_); - end_ = new_end; - mystl::copy_backward(position, end_n, old_end); - mystl::copy(first, last, position); - } - else { - auto mid = first; - mystl::advance(mid, elems_after); - mystl::uninitialized_copy( - position, end_, - mystl::uninitialized_copy(mid, last, end_)); - end_ = new_end; - mystl::copy(first, mid, position); - } - } catch (...) { - if (new_end.node != end_.node) - destroy_buffer(end_.node + 1, new_end.node); - throw; + else { + mystl::uninitialized_fill(end_, position + n, value_copy); + mystl::uninitialized_copy(position, end_, position + n); + end_ = new_end; + mystl::fill(position, old_end, value_copy); } + } catch (...) { + if (new_end.node != end_.node) { + destroy_buffer(end_.node + 1, new_end.node); + } + throw; } } - - // insert_dispatch 函数 - template - template - void deque::insert_dispatch(iterator position, IIter first, IIter last, - input_iterator_tag) { - if (last <= first) - return; - const size_type n = mystl::distance(first, last); - const size_type elems_before = position - begin_; - if (elems_before < (size() / 2)) { - require_capacity(n, true); - } - else { - require_capacity(n, false); - } - position = begin_ + elems_before; - auto cur = --last; - for (size_type i = 0; i < n; ++i, --cur) { - insert(position, *cur); - } - } - - template - template - void deque::insert_dispatch(iterator position, FIter first, FIter last, - forward_iterator_tag) { - if (last <= first) - return; - const size_type n = mystl::distance(first, last); - if (position.cur == begin_.cur) { - require_capacity(n, true); - auto new_begin = begin_ - n; - try { - mystl::uninitialized_copy(first, last, new_begin); +} + +// copy_insert +template +template +void deque::copy_insert(iterator position, FIter first, FIter last, + size_type n) { + const size_type elems_before = position - begin_; + auto len = size(); + if (elems_before < (len / 2)) { + require_capacity(n, true); + // 原来的迭代器可能会失效 + auto old_begin = begin_; + auto new_begin = begin_ - n; + position = begin_ + elems_before; + try { + if (elems_before >= n) { + auto begin_n = begin_ + n; + mystl::uninitialized_copy(begin_, begin_n, new_begin); begin_ = new_begin; - } catch (...) { - if (new_begin.node != begin_.node) - destroy_buffer(new_begin.node, begin_.node - 1); - throw; + mystl::copy(begin_n, position, old_begin); + mystl::copy(first, last, position - n); } - } - else if (position.cur == end_.cur) { - require_capacity(n, false); - auto new_end = end_ + n; - try { - mystl::uninitialized_copy(first, last, end_); - end_ = new_end; - } catch (...) { - if (new_end.node != end_.node) - destroy_buffer(end_.node + 1, new_end.node); - throw; + else { + auto mid = first; + mystl::advance(mid, n - elems_before); + mystl::uninitialized_copy(first, mid, + mystl::uninitialized_copy(begin_, + position, + new_begin)); + begin_ = new_begin; + mystl::copy(mid, last, old_begin); } - } - else { - copy_insert(position, first, last, n); + } catch (...) { + if (new_begin.node != begin_.node) { + destroy_buffer(new_begin.node, begin_.node - 1); + } + throw; } } - - // require_capacity 函数 - template - void deque::require_capacity(size_type n, bool front) { - if (front && (static_cast(begin_.cur - begin_.first) < n)) { - const size_type need_buffer = - (n - (begin_.cur - begin_.first)) / buffer_size + 1; - if (need_buffer > static_cast(begin_.node - map_)) { - reallocate_map_at_front(need_buffer); - return; + else { + require_capacity(n, false); + // 原来的迭代器可能会失效 + auto old_end = end_; + auto new_end = end_ + n; + const auto elems_after = len - elems_before; + position = end_ - elems_after; + try { + if (elems_after > n) { + auto end_n = end_ - n; + mystl::uninitialized_copy(end_n, end_, end_); + end_ = new_end; + mystl::copy_backward(position, end_n, old_end); + mystl::copy(first, last, position); } - create_buffer(begin_.node - need_buffer, begin_.node - 1); - } - else if (!front && - (static_cast(end_.last - end_.cur - 1) < n)) { - const size_type need_buffer = - (n - (end_.last - end_.cur - 1)) / buffer_size + 1; - if (need_buffer > - static_cast((map_ + map_size_) - end_.node - 1)) { - reallocate_map_at_back(need_buffer); - return; + else { + auto mid = first; + mystl::advance(mid, elems_after); + mystl::uninitialized_copy(position, end_, + mystl::uninitialized_copy(mid, last, + end_)); + end_ = new_end; + mystl::copy(first, mid, position); } - create_buffer(end_.node + 1, end_.node + need_buffer); + } catch (...) { + if (new_end.node != end_.node) { + destroy_buffer(end_.node + 1, new_end.node); + } + throw; } } - - // reallocate_map_at_front 函数 - template - void deque::reallocate_map_at_front(size_type need_buffer) { - const size_type new_map_size = mystl::max( - map_size_ << 1, map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE); - map_pointer new_map = create_map(new_map_size); - const size_type old_buffer = end_.node - begin_.node + 1; - const size_type new_buffer = old_buffer + need_buffer; - - // 另新的 map 中的指针指向原来的 buffer,并开辟新的 buffer - auto begin = new_map + (new_map_size - new_buffer) / 2; - auto mid = begin + need_buffer; - auto end = mid + old_buffer; - create_buffer(begin, mid - 1); - for (auto begin1 = mid, begin2 = begin_.node; begin1 != end; - ++begin1, ++begin2) - *begin1 = *begin2; - - // 更新数据 - map_allocator::deallocate(map_, map_size_); - map_ = new_map; - map_size_ = new_map_size; - begin_ = iterator(*mid + (begin_.cur - begin_.first), mid); - end_ = iterator(*(end - 1) + (end_.cur - end_.first), end - 1); - } - - // reallocate_map_at_back 函数 - template - void deque::reallocate_map_at_back(size_type need_buffer) { - const size_type new_map_size = mystl::max( - map_size_ << 1, map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE); - map_pointer new_map = create_map(new_map_size); - const size_type old_buffer = end_.node - begin_.node + 1; - const size_type new_buffer = old_buffer + need_buffer; - - // 另新的 map 中的指针指向原来的 buffer,并开辟新的 buffer - auto begin = new_map + ((new_map_size - new_buffer) / 2); - auto mid = begin + old_buffer; - auto end = mid + need_buffer; - for (auto begin1 = begin, begin2 = begin_.node; begin1 != mid; - ++begin1, ++begin2) - *begin1 = *begin2; - create_buffer(mid, end - 1); - - // 更新数据 - map_allocator::deallocate(map_, map_size_); - map_ = new_map; - map_size_ = new_map_size; - begin_ = iterator(*begin + (begin_.cur - begin_.first), begin); - end_ = iterator(*(mid - 1) + (end_.cur - end_.first), mid - 1); +} + +// insert_dispatch 函数 +template +template +void deque::insert_dispatch(iterator position, IIter first, IIter last, + input_iterator_tag) { + if (last <= first) { + return; } - - // 重载比较操作符 - template - bool operator==(const deque &lhs, const deque &rhs) { - return lhs.size() == rhs.size() && - mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); + const size_type n = mystl::distance(first, last); + const size_type elems_before = position - begin_; + if (elems_before < (size() / 2)) { + require_capacity(n, true); } - - template - bool operator<(const deque &lhs, const deque &rhs) { - return mystl::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end()); + else { + require_capacity(n, false); } - - template - bool operator!=(const deque &lhs, const deque &rhs) { - return !(lhs == rhs); + position = begin_ + elems_before; + auto cur = --last; + for (size_type i = 0; i < n; ++i, --cur) { + insert(position, *cur); } - - template - bool operator>(const deque &lhs, const deque &rhs) { - return rhs < lhs; +} + +template +template +void deque::insert_dispatch(iterator position, FIter first, FIter last, + forward_iterator_tag) { + if (last <= first) { + return; } - - template - bool operator<=(const deque &lhs, const deque &rhs) { - return !(rhs < lhs); + const size_type n = mystl::distance(first, last); + if (position.cur == begin_.cur) { + require_capacity(n, true); + auto new_begin = begin_ - n; + try { + mystl::uninitialized_copy(first, last, new_begin); + begin_ = new_begin; + } catch (...) { + if (new_begin.node != begin_.node) { + destroy_buffer(new_begin.node, begin_.node - 1); + } + throw; + } } - - template - bool operator>=(const deque &lhs, const deque &rhs) { - return !(lhs < rhs); + else if (position.cur == end_.cur) { + require_capacity(n, false); + auto new_end = end_ + n; + try { + mystl::uninitialized_copy(first, last, end_); + end_ = new_end; + } catch (...) { + if (new_end.node != end_.node) { + destroy_buffer(end_.node + 1, new_end.node); + } + throw; + } } - - // 重载 mystl 的 swap - template - void swap(deque &lhs, deque &rhs) { - lhs.swap(rhs); + else { + copy_insert(position, first, last, n); + } +} + +// require_capacity 函数 +template +void deque::require_capacity(size_type n, bool front) { + if (front && (static_cast(begin_.cur - begin_.first) < n)) { + const size_type need_buffer + = (n - (begin_.cur - begin_.first)) / buffer_size + 1; + if (need_buffer > static_cast(begin_.node - map_)) { + reallocate_map_at_front(need_buffer); + return; + } + create_buffer(begin_.node - need_buffer, begin_.node - 1); + } + else if (!front && (static_cast(end_.last - end_.cur - 1) < n)) { + const size_type need_buffer + = (n - (end_.last - end_.cur - 1)) / buffer_size + 1; + if (need_buffer + > static_cast((map_ + map_size_) - end_.node - 1)) { + reallocate_map_at_back(need_buffer); + return; + } + create_buffer(end_.node + 1, end_.node + need_buffer); + } +} + +// reallocate_map_at_front 函数 +template +void deque::reallocate_map_at_front(size_type need_buffer) { + const size_type new_map_size + = mystl::max(map_size_ << 1, + map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE); + map_pointer new_map = create_map(new_map_size); + const size_type old_buffer = end_.node - begin_.node + 1; + const size_type new_buffer = old_buffer + need_buffer; + + // 另新的 map 中的指针指向原来的 buffer,并开辟新的 buffer + auto begin = new_map + (new_map_size - new_buffer) / 2; + auto mid = begin + need_buffer; + auto end = mid + old_buffer; + create_buffer(begin, mid - 1); + for (auto begin1 = mid, begin2 = begin_.node; begin1 != end; + ++begin1, ++begin2) { + *begin1 = *begin2; } -}; - -#endif /* _DEQUE_ */ + // 更新数据 + map_allocator::deallocate(map_, map_size_); + map_ = new_map; + map_size_ = new_map_size; + begin_ = iterator(*mid + (begin_.cur - begin_.first), mid); + end_ = iterator(*(end - 1) + (end_.cur - end_.first), end - 1); +} + +// reallocate_map_at_back 函数 +template +void deque::reallocate_map_at_back(size_type need_buffer) { + const size_type new_map_size + = mystl::max(map_size_ << 1, + map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE); + map_pointer new_map = create_map(new_map_size); + const size_type old_buffer = end_.node - begin_.node + 1; + const size_type new_buffer = old_buffer + need_buffer; + + // 另新的 map 中的指针指向原来的 buffer,并开辟新的 buffer + auto begin = new_map + ((new_map_size - new_buffer) / 2); + auto mid = begin + old_buffer; + auto end = mid + need_buffer; + for (auto begin1 = begin, begin2 = begin_.node; begin1 != mid; + ++begin1, ++begin2) { + *begin1 = *begin2; + } + create_buffer(mid, end - 1); + + // 更新数据 + map_allocator::deallocate(map_, map_size_); + map_ = new_map; + map_size_ = new_map_size; + begin_ = iterator(*begin + (begin_.cur - begin_.first), begin); + end_ = iterator(*(mid - 1) + (end_.cur - end_.first), mid - 1); +} + +// 重载比较操作符 +template +bool operator==(const deque& lhs, const deque& rhs) { + return lhs.size() == rhs.size() + && mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator<(const deque& lhs, const deque& rhs) { + return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), + rhs.end()); +} + +template +bool operator!=(const deque& lhs, const deque& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const deque& lhs, const deque& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const deque& lhs, const deque& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const deque& lhs, const deque& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(deque& lhs, deque& rhs) { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_DEQUE */ diff --git a/src/libcxx/include/exceptdef b/src/libcxx/include/exceptdef index 395f3c5ef..b6d18e133 100644 --- a/src/libcxx/include/exceptdef +++ b/src/libcxx/include/exceptdef @@ -1,11 +1,22 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// exceptdef for Simple-XX/SimpleKernel. - -#ifndef _EXCEPTDEF_ -#define _EXCEPTDEF_ +/** + * @file exceptdef + * @brief stl exceptdef 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_EXCEPTDEF +#define SIMPLEKERNEL_EXCEPTDEF // #include @@ -13,17 +24,17 @@ namespace mystl { -#define MYSTL_DEBUG(expr) assert(expr) +#define MYSTL_DEBUG(expr) assert(expr) -#define THROW_LENGTH_ERROR_IF(expr, what) assert(!(expr)) - // if ((expr)) throw std::length_error(what) +#define THROW_LENGTH_ERROR_IF(expr, what) assert(!(expr)) +// if ((expr)) throw std::length_error(what) -#define THROW_OUT_OF_RANGE_IF(expr, what) assert(!(expr)) - // if ((expr)) throw std::out_of_range(what) +#define THROW_OUT_OF_RANGE_IF(expr, what) assert(!(expr)) +// if ((expr)) throw std::out_of_range(what) #define THROW_RUNTIME_ERROR_IF(expr, what) assert(!(expr)) - // if ((expr)) throw std::runtime_error(what) +// if ((expr)) throw std::runtime_error(what) -}; +}; // namespace mystl -#endif /* _EXCEPTDEF_H_ */ +#endif /* SIMPLEKERNEL_EXCEPTDEF */ diff --git a/src/libcxx/include/functional b/src/libcxx/include/functional index efe0d7fab..0aaac15f8 100644 --- a/src/libcxx/include/functional +++ b/src/libcxx/include/functional @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// functional for Simple-XX/SimpleKernel. - -#ifndef _FUNCTIONAL_ -#define _FUNCTIONAL_ +/** + * @file functional + * @brief stl functional 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_FUNCTIONAL +#define SIMPLEKERNEL_FUNCTIONAL // 这个头文件包含了 std 的函数对象与哈希函数 @@ -13,295 +24,293 @@ namespace mystl { - // 定义一元函数的参数型别和返回值型别 - template - struct unarg_function { - typedef Arg argument_type; - typedef Result result_type; - }; - - // 定义二元函数的参数型别的返回值型别 - template - struct binary_function { - typedef Arg1 first_argument_type; - typedef Arg2 second_argument_type; - typedef Result result_type; - }; - - // 函数对象:加法 - template - struct plus : public binary_function { - T operator()(const T &x, const T &y) const { - return x + y; - } - }; +// 定义一元函数的参数型别和返回值型别 +template +struct unarg_function { + typedef Arg argument_type; + typedef Result result_type; +}; - // 函数对象:减法 - template - struct minus : public binary_function { - T operator()(const T &x, const T &y) const { - return x - y; - } - }; +// 定义二元函数的参数型别的返回值型别 +template +struct binary_function { + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef Result result_type; +}; - // 函数对象:乘法 - template - struct multiplies : public binary_function { - T operator()(const T &x, const T &y) const { - return x * y; - } - }; +// 函数对象:加法 +template +struct plus : public binary_function { + T operator()(const T& x, const T& y) const { + return x + y; + } +}; - // 函数对象:除法 - template - struct divides : public binary_function { - T operator()(const T &x, const T &y) const { - return x / y; - } - }; +// 函数对象:减法 +template +struct minus : public binary_function { + T operator()(const T& x, const T& y) const { + return x - y; + } +}; - // 函数对象:模取 - template - struct modulus : public binary_function { - T operator()(const T &x, const T &y) const { - return x % y; - } - }; +// 函数对象:乘法 +template +struct multiplies : public binary_function { + T operator()(const T& x, const T& y) const { + return x * y; + } +}; - // 函数对象:否定 - template - struct negate : public unarg_function { - T operator()(const T &x) const { - return -x; - } - }; +// 函数对象:除法 +template +struct divides : public binary_function { + T operator()(const T& x, const T& y) const { + return x / y; + } +}; - // 加法的证同元素 - template - T identity_element(plus) { - return T(0); +// 函数对象:模取 +template +struct modulus : public binary_function { + T operator()(const T& x, const T& y) const { + return x % y; } +}; - // 乘法的证同元素 - template - T identity_element(multiplies) { - return T(1); +// 函数对象:否定 +template +struct negate : public unarg_function { + T operator()(const T& x) const { + return -x; } +}; - // 函数对象:等于 - template - struct equal_to : public binary_function { - bool operator()(const T &x, const T &y) const { - return x == y; - } - }; +// 加法的证同元素 +template +T identity_element(plus) { + return T(0); +} + +// 乘法的证同元素 +template +T identity_element(multiplies) { + return T(1); +} + +// 函数对象:等于 +template +struct equal_to : public binary_function { + bool operator()(const T& x, const T& y) const { + return x == y; + } +}; - // 函数对象:不等于 - template - struct not_equal_to : public binary_function { - bool operator()(const T &x, const T &y) const { - return x != y; - } - }; +// 函数对象:不等于 +template +struct not_equal_to : public binary_function { + bool operator()(const T& x, const T& y) const { + return x != y; + } +}; - // 函数对象:大于 - template - struct greater : public binary_function { - bool operator()(const T &x, const T &y) const { - return x > y; - } - }; +// 函数对象:大于 +template +struct greater : public binary_function { + bool operator()(const T& x, const T& y) const { + return x > y; + } +}; - // 函数对象:小于 - template - struct less : public binary_function { - bool operator()(const T &x, const T &y) const { - return x < y; - } - }; +// 函数对象:小于 +template +struct less : public binary_function { + bool operator()(const T& x, const T& y) const { + return x < y; + } +}; - // 函数对象:大于等于 - template - struct greater_equal : public binary_function { - bool operator()(const T &x, const T &y) const { - return x >= y; - } - }; +// 函数对象:大于等于 +template +struct greater_equal : public binary_function { + bool operator()(const T& x, const T& y) const { + return x >= y; + } +}; - // 函数对象:小于等于 - template - struct less_equal : public binary_function { - bool operator()(const T &x, const T &y) const { - return x <= y; - } - }; +// 函数对象:小于等于 +template +struct less_equal : public binary_function { + bool operator()(const T& x, const T& y) const { + return x <= y; + } +}; - // 函数对象:逻辑与 - template - struct logical_and : public binary_function { - bool operator()(const T &x, const T &y) const { - return x && y; - } - }; +// 函数对象:逻辑与 +template +struct logical_and : public binary_function { + bool operator()(const T& x, const T& y) const { + return x && y; + } +}; - // 函数对象:逻辑或 - template - struct logical_or : public binary_function { - bool operator()(const T &x, const T &y) const { - return x || y; - } - }; +// 函数对象:逻辑或 +template +struct logical_or : public binary_function { + bool operator()(const T& x, const T& y) const { + return x || y; + } +}; - // 函数对象:逻辑非 - template - struct logical_not : public unarg_function { - bool operator()(const T &x) const { - return !x; - } - }; +// 函数对象:逻辑非 +template +struct logical_not : public unarg_function { + bool operator()(const T& x) const { + return !x; + } +}; - // 证同函数:不会改变元素,返回本身 - template - struct identity : public unarg_function { - const T &operator()(const T &x) const { - return x; - } - }; +// 证同函数:不会改变元素,返回本身 +template +struct identity : public unarg_function { + const T& operator()(const T& x) const { + return x; + } +}; - // 选择函数:接受一个 pair,返回第一个元素 - template - struct selectfirst - : public unarg_function { - const typename Pair::first_type &operator()(const Pair &x) const { - return x.first; - } - }; +// 选择函数:接受一个 pair,返回第一个元素 +template +struct selectfirst : public unarg_function { + const typename Pair::first_type& operator()(const Pair& x) const { + return x.first; + } +}; - // 选择函数:接受一个 pair,返回第二个元素 - template - struct selectsecond - : public unarg_function { - const typename Pair::second_type &operator()(const Pair &x) const { - return x.second; - } - }; +// 选择函数:接受一个 pair,返回第二个元素 +template +struct selectsecond : public unarg_function { + const typename Pair::second_type& operator()(const Pair& x) const { + return x.second; + } +}; - // 投射函数:返回第一参数 - template - struct projectfirst : public binary_function { - Arg1 operator()(const Arg1 &x, const Arg2 &) const { - return x; - } - }; +// 投射函数:返回第一参数 +template +struct projectfirst : public binary_function { + Arg1 operator()(const Arg1& x, const Arg2&) const { + return x; + } +}; - // 投射函数:返回第二参数 - template - struct projectsecond : public binary_function { - Arg2 operator()(const Arg1 &, const Arg2 &y) const { - return y; - } - }; +// 投射函数:返回第二参数 +template +struct projectsecond : public binary_function { + Arg2 operator()(const Arg1&, const Arg2& y) const { + return y; + } +}; - /*****************************************************************************************/ - // 哈希函数对象 +/*****************************************************************************************/ +// 哈希函数对象 - // 对于大部分类型,hash function 什么都不做 - template - struct hash {}; +// 对于大部分类型,hash function 什么都不做 +template +struct hash { }; - // 针对指针的偏特化版本 - template - struct hash { - size_t operator()(T *p) const noexcept { - return reinterpret_cast(p); - } - }; +// 针对指针的偏特化版本 +template +struct hash { + size_t operator()(T* p) const noexcept { + return reinterpret_cast(p); + } +}; // 对于整型类型,只是返回原值 -#define MYSTL_TRIVIAL_HASH_FCN(Type) \ - template <> \ - struct hash { \ - size_t operator()(Type val) const noexcept { \ - return static_cast(val); \ - } \ +#define MYSTL_TRIVIAL_HASH_FCN(Type) \ + template <> \ + struct hash { \ + size_t operator()(Type val) const noexcept { \ + return static_cast(val); \ + } \ }; - MYSTL_TRIVIAL_HASH_FCN(bool) +MYSTL_TRIVIAL_HASH_FCN(bool) - MYSTL_TRIVIAL_HASH_FCN(char) +MYSTL_TRIVIAL_HASH_FCN(char) - MYSTL_TRIVIAL_HASH_FCN(signed char) +MYSTL_TRIVIAL_HASH_FCN(signed char) - MYSTL_TRIVIAL_HASH_FCN(unsigned char) +MYSTL_TRIVIAL_HASH_FCN(unsigned char) - MYSTL_TRIVIAL_HASH_FCN(wchar_t) +MYSTL_TRIVIAL_HASH_FCN(wchar_t) - MYSTL_TRIVIAL_HASH_FCN(char16_t) +MYSTL_TRIVIAL_HASH_FCN(char16_t) - MYSTL_TRIVIAL_HASH_FCN(char32_t) +MYSTL_TRIVIAL_HASH_FCN(char32_t) - MYSTL_TRIVIAL_HASH_FCN(short) +MYSTL_TRIVIAL_HASH_FCN(short) - MYSTL_TRIVIAL_HASH_FCN(unsigned short) +MYSTL_TRIVIAL_HASH_FCN(unsigned short) - MYSTL_TRIVIAL_HASH_FCN(int) +MYSTL_TRIVIAL_HASH_FCN(int) - MYSTL_TRIVIAL_HASH_FCN(unsigned int) +MYSTL_TRIVIAL_HASH_FCN(unsigned int) - MYSTL_TRIVIAL_HASH_FCN(long) +MYSTL_TRIVIAL_HASH_FCN(long) - MYSTL_TRIVIAL_HASH_FCN(unsigned long) +MYSTL_TRIVIAL_HASH_FCN(unsigned long) - MYSTL_TRIVIAL_HASH_FCN(long long) +MYSTL_TRIVIAL_HASH_FCN(long long) - MYSTL_TRIVIAL_HASH_FCN(unsigned long long) +MYSTL_TRIVIAL_HASH_FCN(unsigned long long) #undef MYSTL_TRIVIAL_HASH_FCN - // 对于浮点数,逐位哈希 - inline size_t bitwise_hash(const unsigned char *first, size_t count) { +// 对于浮点数,逐位哈希 +inline size_t bitwise_hash(const unsigned char* first, size_t count) { #if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) && __SIZEOF_POINTER__ == 8) - const size_t fnv_offset = 14695981039346656037ull; - const size_t fnv_prime = 1099511628211ull; + const size_t fnv_offset = 14695981039346656037ull; + const size_t fnv_prime = 1099511628211ull; #else - const size_t fnv_offset = 2166136261u; - const size_t fnv_prime = 16777619u; + const size_t fnv_offset = 2166136261u; + const size_t fnv_prime = 16777619u; #endif - size_t result = fnv_offset; - for (size_t i = 0; i < count; ++i) { - result ^= (size_t)first[i]; - result *= fnv_prime; - } - return result; + size_t result = fnv_offset; + for (size_t i = 0; i < count; ++i) { + result ^= (size_t)first[i]; + result *= fnv_prime; } + return result; +} + +template <> +struct hash { + size_t operator()(const float& val) { + return val == 0.0f + ? 0 + : bitwise_hash((const unsigned char*)&val, sizeof(float)); + } +}; - template <> - struct hash { - size_t operator()(const float &val) { - return val == 0.0f ? 0 - : bitwise_hash((const unsigned char *)&val, - sizeof(float)); - } - }; - - template <> - struct hash { - size_t operator()(const double &val) { - return val == 0.0f ? 0 - : bitwise_hash((const unsigned char *)&val, - sizeof(double)); - } - }; - - template <> - struct hash { - size_t operator()(const long double &val) { - return val == 0.0f ? 0 - : bitwise_hash((const unsigned char *)&val, - sizeof(long double)); - } - }; +template <> +struct hash { + size_t operator()(const double& val) { + return val == 0.0f + ? 0 + : bitwise_hash((const unsigned char*)&val, sizeof(double)); + } +}; +template <> +struct hash { + size_t operator()(const long double& val) { + return val == 0.0f + ? 0 + : bitwise_hash((const unsigned char*)&val, sizeof(long double)); + } }; -#endif /* _FUNCTIONAL_ */ +}; // namespace mystl + +#endif /* SIMPLEKERNEL_FUNCTIONAL */ diff --git a/src/libcxx/include/hashtable b/src/libcxx/include/hashtable index 15efba90e..d4e5e9843 100644 --- a/src/libcxx/include/hashtable +++ b/src/libcxx/include/hashtable @@ -1,1579 +1,1655 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// hashtable for Simple-XX/SimpleKernel. - -#ifndef _HASHTABLE_ -#define _HASHTABLE_ +/** + * @file hashtable + * @brief stl hashtable 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_HASHTABLE +#define SIMPLEKERNEL_HASHTABLE // 这个头文件包含了一个模板类 hashtable // hashtable : 哈希表,使用开链法处理冲突 -#include "initializer_list" #include "algo" +#include "exceptdef" #include "functional" +#include "initializer_list" #include "memory" -#include "vector" #include "util" -#include "exceptdef" +#include "vector" namespace mystl { - // hashtable 的节点定义 - template - struct hashtable_node { - hashtable_node *next; // 指向下一个节点 - T value; // 储存实值 +// hashtable 的节点定义 +template +struct hashtable_node { + hashtable_node* next; // 指向下一个节点 + T value; // 储存实值 - hashtable_node() = default; - hashtable_node(const T &n) : next(nullptr), value(n) { - } + hashtable_node() = default; - hashtable_node(const hashtable_node &node) - : next(node.next), value(node.value) { - } - hashtable_node(hashtable_node &&node) - : next(node.next), value(mystl::move(node.value)) { - node.next = nullptr; - } - }; - - // value traits - template - struct ht_value_traits_imp { - typedef T key_type; - typedef T mapped_type; - typedef T value_type; - - template - static const key_type &get_key(const Ty &value) { - return value; - } + hashtable_node(const T& n) : next(nullptr), value(n) { + } - template - static const value_type &get_value(const Ty &value) { - return value; - } - }; + hashtable_node(const hashtable_node& node) + : next(node.next), value(node.value) { + } - template - struct ht_value_traits_imp { - typedef typename std::remove_cv::type key_type; - typedef typename T::second_type mapped_type; - typedef T value_type; + hashtable_node(hashtable_node&& node) + : next(node.next), value(mystl::move(node.value)) { + node.next = nullptr; + } +}; - template - static const key_type &get_key(const Ty &value) { - return value.first; - } +// value traits +template +struct ht_value_traits_imp { + typedef T key_type; + typedef T mapped_type; + typedef T value_type; - template - static const value_type &get_value(const Ty &value) { - return value; - } - }; + template + static const key_type& get_key(const Ty& value) { + return value; + } - template - struct ht_value_traits { - static constexpr bool is_map = mystl::is_pair::value; + template + static const value_type& get_value(const Ty& value) { + return value; + } +}; - typedef ht_value_traits_imp value_traits_type; +template +struct ht_value_traits_imp { + typedef typename std::remove_cv::type key_type; + typedef typename T::second_type mapped_type; + typedef T value_type; - typedef typename value_traits_type::key_type key_type; - typedef typename value_traits_type::mapped_type mapped_type; - typedef typename value_traits_type::value_type value_type; + template + static const key_type& get_key(const Ty& value) { + return value.first; + } - template - static const key_type &get_key(const Ty &value) { - return value_traits_type::get_key(value); - } + template + static const value_type& get_value(const Ty& value) { + return value; + } +}; - template - static const value_type &get_value(const Ty &value) { - return value_traits_type::get_value(value); - } - }; +template +struct ht_value_traits { + static constexpr bool is_map = mystl::is_pair::value; - // forward declaration + typedef ht_value_traits_imp value_traits_type; - template - class hashtable; + typedef typename value_traits_type::key_type key_type; + typedef typename value_traits_type::mapped_type mapped_type; + typedef typename value_traits_type::value_type value_type; - template - struct ht_iterator; + template + static const key_type& get_key(const Ty& value) { + return value_traits_type::get_key(value); + } - template - struct ht_const_iterator; + template + static const value_type& get_value(const Ty& value) { + return value_traits_type::get_value(value); + } +}; - template - struct ht_local_iterator; +// forward declaration - template - struct ht_const_local_iterator; +template +class hashtable; - // ht_iterator +template +struct ht_iterator; - template - struct ht_iterator_base - : public mystl::iterator { - typedef mystl::hashtable hashtable; - typedef ht_iterator_base base; - typedef mystl::ht_iterator iterator; - typedef mystl::ht_const_iterator const_iterator; - typedef hashtable_node * node_ptr; - typedef hashtable * contain_ptr; - typedef const node_ptr const_node_ptr; - typedef const contain_ptr const_contain_ptr; +template +struct ht_const_iterator; - typedef size_t size_type; - typedef ptrdiff_t difference_type; +template +struct ht_local_iterator; - node_ptr node; // 迭代器当前所指节点 - contain_ptr ht; // 保持与容器的连结 +template +struct ht_const_local_iterator; - ht_iterator_base() = default; +// ht_iterator - bool operator==(const base &rhs) const { - return node == rhs.node; - } - bool operator!=(const base &rhs) const { - return node != rhs.node; - } - }; - - template - struct ht_iterator : public ht_iterator_base { - typedef ht_iterator_base base; - typedef typename base::hashtable hashtable; - typedef typename base::iterator iterator; - typedef typename base::const_iterator const_iterator; - typedef typename base::node_ptr node_ptr; - typedef typename base::contain_ptr contain_ptr; - - typedef ht_value_traits value_traits; - typedef T value_type; - typedef value_type * pointer; - typedef value_type & reference; - - using base::ht; - using base::node; - - ht_iterator() = default; - ht_iterator(node_ptr n, contain_ptr t) { - node = n; - ht = t; - } - ht_iterator(const iterator &rhs) { +template +struct ht_iterator_base + : public mystl::iterator { + typedef mystl::hashtable hashtable; + typedef ht_iterator_base base; + typedef mystl::ht_iterator iterator; + typedef mystl::ht_const_iterator const_iterator; + typedef hashtable_node* node_ptr; + typedef hashtable* contain_ptr; + typedef const node_ptr const_node_ptr; + typedef const contain_ptr const_contain_ptr; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + node_ptr node; // 迭代器当前所指节点 + contain_ptr ht; // 保持与容器的连结 + + ht_iterator_base() = default; + + bool operator==(const base& rhs) const { + return node == rhs.node; + } + + bool operator!=(const base& rhs) const { + return node != rhs.node; + } +}; + +template +struct ht_iterator : public ht_iterator_base { + typedef ht_iterator_base base; + typedef typename base::hashtable hashtable; + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + typedef typename base::node_ptr node_ptr; + typedef typename base::contain_ptr contain_ptr; + + typedef ht_value_traits value_traits; + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + + using base::ht; + using base::node; + + ht_iterator() = default; + + ht_iterator(node_ptr n, contain_ptr t) { + node = n; + ht = t; + } + + ht_iterator(const iterator& rhs) { + node = rhs.node; + ht = rhs.ht; + } + + ht_iterator(const const_iterator& rhs) { + node = rhs.node; + ht = rhs.ht; + } + + iterator& operator=(const iterator& rhs) { + if (this != &rhs) { node = rhs.node; ht = rhs.ht; } - ht_iterator(const const_iterator &rhs) { + return *this; + } + + iterator& operator=(const const_iterator& rhs) { + if (this != &rhs) { node = rhs.node; ht = rhs.ht; } - iterator &operator=(const iterator &rhs) { - if (this != &rhs) { - node = rhs.node; - ht = rhs.ht; - } - return *this; - } - iterator &operator=(const const_iterator &rhs) { - if (this != &rhs) { - node = rhs.node; - ht = rhs.ht; - } - return *this; - } + return *this; + } - // 重载操作符 - reference operator*() const { - return node->value; - } - pointer operator->() const { - return &(operator*()); - } + // 重载操作符 + reference operator*() const { + return node->value; + } - iterator &operator++() { - MYSTL_DEBUG(node != nullptr); - const node_ptr old = node; - node = node->next; - if (node == - nullptr) { // 如果下一个位置为空,跳到下一个 bucket 的起始处 - auto index = ht->hash(value_traits::get_key(old->value)); - while (!node && ++index < ht->bucket_size_) - node = ht->buckets_[index]; + pointer operator->() const { + return &(operator*()); + } + + iterator& operator++() { + MYSTL_DEBUG(node != nullptr); + const node_ptr old = node; + node = node->next; + if (node + == nullptr) { // 如果下一个位置为空,跳到下一个 bucket 的起始处 + auto index = ht->hash(value_traits::get_key(old->value)); + while (!node && ++index < ht->bucket_size_) { + node = ht->buckets_[index]; } - return *this; - } - iterator operator++(int) { - iterator tmp = *this; - ++*this; - return tmp; - } - }; - - template - struct ht_const_iterator : public ht_iterator_base { - typedef ht_iterator_base base; - typedef typename base::hashtable hashtable; - typedef typename base::iterator iterator; - typedef typename base::const_iterator const_iterator; - typedef typename base::const_node_ptr node_ptr; - typedef typename base::const_contain_ptr contain_ptr; - - typedef ht_value_traits value_traits; - typedef T value_type; - typedef const value_type * pointer; - typedef const value_type & reference; - - using base::ht; - using base::node; - - ht_const_iterator() = default; - ht_const_iterator(node_ptr n, contain_ptr t) { - node = n; - ht = t; } - ht_const_iterator(const iterator &rhs) { + return *this; + } + + iterator operator++(int) { + iterator tmp = *this; + ++*this; + return tmp; + } +}; + +template +struct ht_const_iterator : public ht_iterator_base { + typedef ht_iterator_base base; + typedef typename base::hashtable hashtable; + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + typedef typename base::const_node_ptr node_ptr; + typedef typename base::const_contain_ptr contain_ptr; + + typedef ht_value_traits value_traits; + typedef T value_type; + typedef const value_type* pointer; + typedef const value_type& reference; + + using base::ht; + using base::node; + + ht_const_iterator() = default; + + ht_const_iterator(node_ptr n, contain_ptr t) { + node = n; + ht = t; + } + + ht_const_iterator(const iterator& rhs) { + node = rhs.node; + ht = rhs.ht; + } + + ht_const_iterator(const const_iterator& rhs) { + node = rhs.node; + ht = rhs.ht; + } + + const_iterator& operator=(const iterator& rhs) { + if (this != &rhs) { node = rhs.node; ht = rhs.ht; } - ht_const_iterator(const const_iterator &rhs) { + return *this; + } + + const_iterator& operator=(const const_iterator& rhs) { + if (this != &rhs) { node = rhs.node; ht = rhs.ht; } - const_iterator &operator=(const iterator &rhs) { - if (this != &rhs) { - node = rhs.node; - ht = rhs.ht; - } - return *this; - } - const_iterator &operator=(const const_iterator &rhs) { - if (this != &rhs) { - node = rhs.node; - ht = rhs.ht; - } - return *this; - } + return *this; + } - // 重载操作符 - reference operator*() const { - return node->value; - } - pointer operator->() const { - return &(operator*()); - } + // 重载操作符 + reference operator*() const { + return node->value; + } - const_iterator &operator++() { - MYSTL_DEBUG(node != nullptr); - const node_ptr old = node; - node = node->next; - if (node == - nullptr) { // 如果下一个位置为空,跳到下一个 bucket 的起始处 - auto index = ht->hash(value_traits::get_key(old->value)); - while (!node && ++index < ht->bucket_size_) { - node = ht->buckets_[index]; - } + pointer operator->() const { + return &(operator*()); + } + + const_iterator& operator++() { + MYSTL_DEBUG(node != nullptr); + const node_ptr old = node; + node = node->next; + if (node + == nullptr) { // 如果下一个位置为空,跳到下一个 bucket 的起始处 + auto index = ht->hash(value_traits::get_key(old->value)); + while (!node && ++index < ht->bucket_size_) { + node = ht->buckets_[index]; } - return *this; - } - const_iterator operator++(int) { - const_iterator tmp = *this; - ++*this; - return tmp; - } - }; - - // local iterator - template - struct ht_local_iterator - : public mystl::iterator { - typedef T value_type; - typedef value_type * pointer; - typedef value_type & reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef hashtable_node *node_ptr; - - typedef ht_local_iterator self; - typedef ht_local_iterator local_iterator; - typedef ht_const_local_iterator const_local_iterator; - node_ptr node; - - ht_local_iterator(node_ptr n) : node(n) { - } - ht_local_iterator(const local_iterator &rhs) : node(rhs.node) { - } - ht_local_iterator(const const_local_iterator &rhs) : node(rhs.node) { } + return *this; + } - reference operator*() const { - return node->value; - } - pointer operator->() const { - return &(operator*()); - } + const_iterator operator++(int) { + const_iterator tmp = *this; + ++*this; + return tmp; + } +}; - self &operator++() { - MYSTL_DEBUG(node != nullptr); - node = node->next; - return *this; - } +// local iterator +template +struct ht_local_iterator + : public mystl::iterator { + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef hashtable_node* node_ptr; + + typedef ht_local_iterator self; + typedef ht_local_iterator local_iterator; + typedef ht_const_local_iterator const_local_iterator; + node_ptr node; + + ht_local_iterator(node_ptr n) : node(n) { + } - self operator++(int) { - self tmp(*this); - ++*this; - return tmp; - } + ht_local_iterator(const local_iterator& rhs) : node(rhs.node) { + } - bool operator==(const self &other) const { - return node == other.node; - } - bool operator!=(const self &other) const { - return node != other.node; - } - }; + ht_local_iterator(const const_local_iterator& rhs) : node(rhs.node) { + } - template - struct ht_const_local_iterator - : public mystl::iterator { - typedef T value_type; - typedef const value_type * pointer; - typedef const value_type & reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef const hashtable_node *node_ptr; + reference operator*() const { + return node->value; + } - typedef ht_const_local_iterator self; - typedef ht_local_iterator local_iterator; - typedef ht_const_local_iterator const_local_iterator; + pointer operator->() const { + return &(operator*()); + } - node_ptr node; + self& operator++() { + MYSTL_DEBUG(node != nullptr); + node = node->next; + return *this; + } - ht_const_local_iterator(node_ptr n) : node(n) { - } - ht_const_local_iterator(const local_iterator &rhs) : node(rhs.node) { - } - ht_const_local_iterator(const const_local_iterator &rhs) - : node(rhs.node) { - } + self operator++(int) { + self tmp(*this); + ++*this; + return tmp; + } - reference operator*() const { - return node->value; - } - pointer operator->() const { - return &(operator*()); - } + bool operator==(const self& other) const { + return node == other.node; + } - self &operator++() { - MYSTL_DEBUG(node != nullptr); - node = node->next; - return *this; - } + bool operator!=(const self& other) const { + return node != other.node; + } +}; - self operator++(int) { - self tmp(*this); - ++*this; - return tmp; - } +template +struct ht_const_local_iterator + : public mystl::iterator { + typedef T value_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef const hashtable_node* node_ptr; - bool operator==(const self &other) const { - return node == other.node; - } - bool operator!=(const self &other) const { - return node != other.node; - } - }; + typedef ht_const_local_iterator self; + typedef ht_local_iterator local_iterator; + typedef ht_const_local_iterator const_local_iterator; + + node_ptr node; + + ht_const_local_iterator(node_ptr n) : node(n) { + } + + ht_const_local_iterator(const local_iterator& rhs) : node(rhs.node) { + } + + ht_const_local_iterator(const const_local_iterator& rhs) : node(rhs.node) { + } - // bucket 使用的大小 + reference operator*() const { + return node->value; + } + + pointer operator->() const { + return &(operator*()); + } + + self& operator++() { + MYSTL_DEBUG(node != nullptr); + node = node->next; + return *this; + } + + self operator++(int) { + self tmp(*this); + ++*this; + return tmp; + } + + bool operator==(const self& other) const { + return node == other.node; + } + + bool operator!=(const self& other) const { + return node != other.node; + } +}; + +// bucket 使用的大小 #if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) && __SIZEOF_POINTER__ == 8) -#define SYSTEM_64 1 +# define SYSTEM_64 1 #else -#define SYSTEM_32 1 +# define SYSTEM_32 1 #endif #ifdef SYSTEM_64 -#define PRIME_NUM 99 - - // 1. start with p = 101 - // 2. p = next_prime(p * 1.7) - // 3. if p < (2 << 63), go to step 2, otherwise, go to step 4 - // 4. end with p = prev_prime(2 << 63 - 1) - static constexpr size_t ht_prime_list[] = {101ull, - 173ull, - 263ull, - 397ull, - 599ull, - 907ull, - 1361ull, - 2053ull, - 3083ull, - 4637ull, - 6959ull, - 10453ull, - 15683ull, - 23531ull, - 35311ull, - 52967ull, - 79451ull, - 119179ull, - 178781ull, - 268189ull, - 402299ull, - 603457ull, - 905189ull, - 1357787ull, - 2036687ull, - 3055043ull, - 4582577ull, - 6873871ull, - 10310819ull, - 15466229ull, - 23199347ull, - 34799021ull, - 52198537ull, - 78297827ull, - 117446801ull, - 176170229ull, - 264255353ull, - 396383041ull, - 594574583ull, - 891861923ull, - 1337792887ull, - 2006689337ull, - 3010034021ull, - 4515051137ull, - 6772576709ull, - 10158865069ull, - 15238297621ull, - 22857446471ull, - 34286169707ull, - 51429254599ull, - 77143881917ull, - 115715822899ull, - 173573734363ull, - 260360601547ull, - 390540902329ull, - 585811353559ull, - 878717030339ull, - 1318075545511ull, - 1977113318311ull, - 2965669977497ull, - 4448504966249ull, - 6672757449409ull, - 10009136174239ull, - 15013704261371ull, - 22520556392057ull, - 33780834588157ull, - 50671251882247ull, - 76006877823377ull, - 114010316735089ull, - 171015475102649ull, - 256523212653977ull, - 384784818980971ull, - 577177228471507ull, - 865765842707309ull, - 1298648764060979ull, - 1947973146091477ull, - 2921959719137273ull, - 4382939578705967ull, - 6574409368058969ull, - 9861614052088471ull, - 14792421078132871ull, - 22188631617199337ull, - 33282947425799017ull, - 49924421138698549ull, - 74886631708047827ull, - 112329947562071807ull, - 168494921343107851ull, - 252742382014661767ull, - 379113573021992729ull, - 568670359532989111ull, - 853005539299483657ull, - 1279508308949225477ull, - 1919262463423838231ull, - 2878893695135757317ull, - 4318340542703636011ull, - 6477510814055453699ull, - 9716266221083181299ull, - 14574399331624771603ull, - 18446744073709551557ull}; +# define PRIME_NUM 99 + +// 1. start with p = 101 +// 2. p = next_prime(p * 1.7) +// 3. if p < (2 << 63), go to step 2, otherwise, go to step 4 +// 4. end with p = prev_prime(2 << 63 - 1) +static constexpr size_t ht_prime_list[] = { 101ull, + 173ull, + 263ull, + 397ull, + 599ull, + 907ull, + 1361ull, + 2053ull, + 3083ull, + 4637ull, + 6959ull, + 10453ull, + 15683ull, + 23531ull, + 35311ull, + 52967ull, + 79451ull, + 119179ull, + 178781ull, + 268189ull, + 402299ull, + 603457ull, + 905189ull, + 1357787ull, + 2036687ull, + 3055043ull, + 4582577ull, + 6873871ull, + 10310819ull, + 15466229ull, + 23199347ull, + 34799021ull, + 52198537ull, + 78297827ull, + 117446801ull, + 176170229ull, + 264255353ull, + 396383041ull, + 594574583ull, + 891861923ull, + 1337792887ull, + 2006689337ull, + 3010034021ull, + 4515051137ull, + 6772576709ull, + 10158865069ull, + 15238297621ull, + 22857446471ull, + 34286169707ull, + 51429254599ull, + 77143881917ull, + 115715822899ull, + 173573734363ull, + 260360601547ull, + 390540902329ull, + 585811353559ull, + 878717030339ull, + 1318075545511ull, + 1977113318311ull, + 2965669977497ull, + 4448504966249ull, + 6672757449409ull, + 10009136174239ull, + 15013704261371ull, + 22520556392057ull, + 33780834588157ull, + 50671251882247ull, + 76006877823377ull, + 114010316735089ull, + 171015475102649ull, + 256523212653977ull, + 384784818980971ull, + 577177228471507ull, + 865765842707309ull, + 1298648764060979ull, + 1947973146091477ull, + 2921959719137273ull, + 4382939578705967ull, + 6574409368058969ull, + 9861614052088471ull, + 14792421078132871ull, + 22188631617199337ull, + 33282947425799017ull, + 49924421138698549ull, + 74886631708047827ull, + 112329947562071807ull, + 168494921343107851ull, + 252742382014661767ull, + 379113573021992729ull, + 568670359532989111ull, + 853005539299483657ull, + 1279508308949225477ull, + 1919262463423838231ull, + 2878893695135757317ull, + 4318340542703636011ull, + 6477510814055453699ull, + 9716266221083181299ull, + 14574399331624771603ull, + 18446744073709551557ull }; #else -#define PRIME_NUM 44 - - // 1. start with p = 101 - // 2. p = next_prime(p * 1.7) - // 3. if p < (2 << 31), go to step 2, otherwise, go to step 4 - // 4. end with p = prev_prime(2 << 31 - 1) - static constexpr size_t ht_prime_list[] = { - 101u, 173u, 263u, 397u, 599u, - 907u, 1361u, 2053u, 3083u, 4637u, - 6959u, 10453u, 15683u, 23531u, 35311u, - 52967u, 79451u, 119179u, 178781u, 268189u, - 402299u, 603457u, 905189u, 1357787u, 2036687u, - 3055043u, 4582577u, 6873871u, 10310819u, 15466229u, - 23199347u, 34799021u, 52198537u, 78297827u, 117446801u, - 176170229u, 264255353u, 396383041u, 594574583u, 891861923u, - 1337792887u, 2006689337u, 3010034021u, 4294967291u, - }; +# define PRIME_NUM 44 + +// 1. start with p = 101 +// 2. p = next_prime(p * 1.7) +// 3. if p < (2 << 31), go to step 2, otherwise, go to step 4 +// 4. end with p = prev_prime(2 << 31 - 1) +static constexpr size_t ht_prime_list[] = { + 101u, 173u, 263u, 397u, 599u, 907u, + 1361u, 2053u, 3083u, 4637u, 6959u, 10453u, + 15683u, 23531u, 35311u, 52967u, 79451u, 119179u, + 178781u, 268189u, 402299u, 603457u, 905189u, 1357787u, + 2036687u, 3055043u, 4582577u, 6873871u, 10310819u, 15466229u, + 23199347u, 34799021u, 52198537u, 78297827u, 117446801u, 176170229u, + 264255353u, 396383041u, 594574583u, 891861923u, 1337792887u, 2006689337u, + 3010034021u, 4294967291u, +}; #endif - // 找出最接近并大于等于 n 的那个质数 - inline size_t ht_next_prime(size_t n) { - const size_t *first = ht_prime_list; - const size_t *last = ht_prime_list + PRIME_NUM; - const size_t *pos = mystl::lower_bound(first, last, n); - return pos == last ? *(last - 1) : *pos; - } - - // 模板类 hashtable - // 参数一代表数据类型,参数二代表哈希函数,参数三代表键值相等的比较函数 - template - class hashtable { - - friend struct mystl::ht_iterator; - friend struct mystl::ht_const_iterator; - - public: - // hashtable 的型别定义 - typedef ht_value_traits value_traits; - typedef typename value_traits::key_type key_type; - typedef typename value_traits::mapped_type mapped_type; - typedef typename value_traits::value_type value_type; - typedef Hash hasher; - typedef KeyEqual key_equal; - - typedef hashtable_node node_type; - typedef node_type * node_ptr; - typedef mystl::vector bucket_type; - - typedef mystl::allocator allocator_type; - typedef mystl::allocator data_allocator; - typedef mystl::allocator node_allocator; - - typedef typename allocator_type::pointer pointer; - typedef typename allocator_type::const_pointer const_pointer; - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - typedef typename allocator_type::size_type size_type; - typedef typename allocator_type::difference_type difference_type; - - typedef mystl::ht_iterator iterator; - typedef mystl::ht_const_iterator const_iterator; - typedef mystl::ht_local_iterator local_iterator; - typedef mystl::ht_const_local_iterator const_local_iterator; - - allocator_type get_allocator() const { - return allocator_type(); - } +// 找出最接近并大于等于 n 的那个质数 +inline size_t ht_next_prime(size_t n) { + const size_t* first = ht_prime_list; + const size_t* last = ht_prime_list + PRIME_NUM; + const size_t* pos = mystl::lower_bound(first, last, n); + return pos == last ? *(last - 1) : *pos; +} + +// 模板类 hashtable +// 参数一代表数据类型,参数二代表哈希函数,参数三代表键值相等的比较函数 +template +class hashtable { + friend struct mystl::ht_iterator; + friend struct mystl::ht_const_iterator; + +public: + // hashtable 的型别定义 + typedef ht_value_traits value_traits; + typedef typename value_traits::key_type key_type; + typedef typename value_traits::mapped_type mapped_type; + typedef typename value_traits::value_type value_type; + typedef Hash hasher; + typedef KeyEqual key_equal; + + typedef hashtable_node node_type; + typedef node_type* node_ptr; + typedef mystl::vector bucket_type; + + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator node_allocator; + + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef mystl::ht_iterator iterator; + typedef mystl::ht_const_iterator const_iterator; + typedef mystl::ht_local_iterator local_iterator; + typedef mystl::ht_const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { + return allocator_type(); + } - private: - // 用以下六个参数来表现 hashtable - bucket_type buckets_; - size_type bucket_size_; - size_type size_; - float mlf_; - hasher hash_; - key_equal equal_; - - private: - bool is_equal(const key_type &key1, const key_type &key2) { - return equal_(key1, key2); - } +private: + // 用以下六个参数来表现 hashtable + bucket_type buckets_; + size_type bucket_size_; + size_type size_; + float mlf_; + hasher hash_; + key_equal equal_; + +private: + bool is_equal(const key_type& key1, const key_type& key2) { + return equal_(key1, key2); + } - bool is_equal(const key_type &key1, const key_type &key2) const { - return equal_(key1, key2); - } + bool is_equal(const key_type& key1, const key_type& key2) const { + return equal_(key1, key2); + } - const_iterator M_cit(node_ptr node) const noexcept { - return const_iterator(node, const_cast(this)); - } + const_iterator M_cit(node_ptr node) const noexcept { + return const_iterator(node, const_cast(this)); + } - iterator M_begin() noexcept { - for (size_type n = 0; n < bucket_size_; ++n) { - if (buckets_[n]) // 找到第一个有节点的位置就返回 - return iterator(buckets_[n], this); + iterator M_begin() noexcept { + for (size_type n = 0; n < bucket_size_; ++n) { + if (buckets_[n]) { // 找到第一个有节点的位置就返回 + return iterator(buckets_[n], this); } - return iterator(nullptr, this); } + return iterator(nullptr, this); + } - const_iterator M_begin() const noexcept { - for (size_type n = 0; n < bucket_size_; ++n) { - if (buckets_[n]) // 找到第一个有节点的位置就返回 - return M_cit(buckets_[n]); + const_iterator M_begin() const noexcept { + for (size_type n = 0; n < bucket_size_; ++n) { + if (buckets_[n]) { // 找到第一个有节点的位置就返回 + return M_cit(buckets_[n]); } - return M_cit(nullptr); } + return M_cit(nullptr); + } - public: - // 构造、复制、移动、析构函数 - explicit hashtable(size_type bucket_count, const Hash &hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : size_(0), mlf_(1.0f), hash_(hash), equal_(equal) { - init(bucket_count); - } +public: + // 构造、复制、移动、析构函数 + explicit hashtable(size_type bucket_count, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : size_(0), mlf_(1.0f), hash_(hash), equal_(equal) { + init(bucket_count); + } - template ::value, - int>::type = 0> - hashtable(Iter first, Iter last, size_type bucket_count, - const Hash &hash = Hash(), const KeyEqual &equal = KeyEqual()) - : size_(mystl::distance(first, last)), mlf_(1.0f), hash_(hash), - equal_(equal) { - init(mystl::max(bucket_count, static_cast( - mystl::distance(first, last)))); - } + template ::value, int>::type + = 0> + hashtable(Iter first, Iter last, size_type bucket_count, + const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual()) + : size_(mystl::distance(first, last)), + mlf_(1.0f), + hash_(hash), + equal_(equal) { + init(mystl::max(bucket_count, + static_cast(mystl::distance(first, last)))); + } - hashtable(const hashtable &rhs) : hash_(rhs.hash_), equal_(rhs.equal_) { - copy_init(rhs); - } - hashtable(hashtable &&rhs) noexcept - : bucket_size_(rhs.bucket_size_), size_(rhs.size_), mlf_(rhs.mlf_), - hash_(rhs.hash_), equal_(rhs.equal_) { - buckets_ = mystl::move(rhs.buckets_); - rhs.bucket_size_ = 0; - rhs.size_ = 0; - rhs.mlf_ = 0.0f; - } + hashtable(const hashtable& rhs) : hash_(rhs.hash_), equal_(rhs.equal_) { + copy_init(rhs); + } - hashtable &operator=(const hashtable &rhs); - hashtable &operator=(hashtable &&rhs) noexcept; + hashtable(hashtable&& rhs) noexcept + : bucket_size_(rhs.bucket_size_), + size_(rhs.size_), + mlf_(rhs.mlf_), + hash_(rhs.hash_), + equal_(rhs.equal_) { + buckets_ = mystl::move(rhs.buckets_); + rhs.bucket_size_ = 0; + rhs.size_ = 0; + rhs.mlf_ = 0.0f; + } - ~hashtable() { - clear(); - } + hashtable& operator=(const hashtable& rhs); + hashtable& operator=(hashtable&& rhs) noexcept; - // 迭代器相关操作 - iterator begin() noexcept { - return M_begin(); - } - const_iterator begin() const noexcept { - return M_begin(); - } - iterator end() noexcept { - return iterator(nullptr, this); - } - const_iterator end() const noexcept { - return M_cit(nullptr); - } + ~hashtable() { + clear(); + } - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } + // 迭代器相关操作 + iterator begin() noexcept { + return M_begin(); + } - // 容量相关操作 - bool empty() const noexcept { - return size_ == 0; - } - size_type size() const noexcept { - return size_; - } - size_type max_size() const noexcept { - return static_cast(-1); - } + const_iterator begin() const noexcept { + return M_begin(); + } - // 修改容器相关操作 + iterator end() noexcept { + return iterator(nullptr, this); + } - // emplace / empalce_hint + const_iterator end() const noexcept { + return M_cit(nullptr); + } - template - iterator emplace_multi(Args &&...args); + const_iterator cbegin() const noexcept { + return begin(); + } - template - pair emplace_unique(Args &&...args); + const_iterator cend() const noexcept { + return end(); + } - // [note]: hint 对于 hash_table 其实没有意义,因为即使提供了 - // hint,也要做一次 hash, 来确保 hash_table 的性质,所以选择忽略它 - template - iterator emplace_multi_use_hint(const_iterator /*hint*/, - Args &&...args) { - return emplace_multi(mystl::forward(args)...); - } + // 容量相关操作 + bool empty() const noexcept { + return size_ == 0; + } - template - iterator emplace_unique_use_hint(const_iterator /*hint*/, - Args &&...args) { - return emplace_unique(mystl::forward(args)...).first; - } + size_type size() const noexcept { + return size_; + } - // insert + size_type max_size() const noexcept { + return static_cast(-1); + } - iterator insert_multi_noresize(const value_type &value); - pair insert_unique_noresize(const value_type &value); + // 修改容器相关操作 - iterator insert_multi(const value_type &value) { - rehash_if_need(1); - return insert_multi_noresize(value); - } - iterator insert_multi(value_type &&value) { - return emplace_multi(mystl::move(value)); - } + // emplace / empalce_hint - pair insert_unique(const value_type &value) { - rehash_if_need(1); - return insert_unique_noresize(value); - } - pair insert_unique(value_type &&value) { - return emplace_unique(mystl::move(value)); - } + template + iterator emplace_multi(Args&&... args); - // [note]: 同 emplace_hint - iterator insert_multi_use_hint(const_iterator /*hint*/, - const value_type &value) { - return insert_multi(value); - } - iterator insert_multi_use_hint(const_iterator /*hint*/, - value_type &&value) { - return emplace_multi(mystl::move(value)); - } + template + pair emplace_unique(Args&&... args); - iterator insert_unique_use_hint(const_iterator /*hint*/, - const value_type &value) { - return insert_unique(value).first; - } - iterator insert_unique_use_hint(const_iterator /*hint*/, - value_type &&value) { - return emplace_unique(mystl::move(value)); - } + // [note]: hint 对于 hash_table 其实没有意义,因为即使提供了 + // hint,也要做一次 hash, 来确保 hash_table 的性质,所以选择忽略它 + template + iterator emplace_multi_use_hint(const_iterator /*hint*/, Args&&... args) { + return emplace_multi(mystl::forward(args)...); + } - template - void insert_multi(InputIter first, InputIter last) { - copy_insert_multi(first, last, iterator_category(first)); - } + template + iterator emplace_unique_use_hint(const_iterator /*hint*/, Args&&... args) { + return emplace_unique(mystl::forward(args)...).first; + } - template - void insert_unique(InputIter first, InputIter last) { - copy_insert_unique(first, last, iterator_category(first)); - } + // insert - // erase / clear + iterator insert_multi_noresize(const value_type& value); + pair insert_unique_noresize(const value_type& value); - void erase(const_iterator position); - void erase(const_iterator first, const_iterator last); + iterator insert_multi(const value_type& value) { + rehash_if_need(1); + return insert_multi_noresize(value); + } - size_type erase_multi(const key_type &key); - size_type erase_unique(const key_type &key); + iterator insert_multi(value_type&& value) { + return emplace_multi(mystl::move(value)); + } - void clear(); + pair insert_unique(const value_type& value) { + rehash_if_need(1); + return insert_unique_noresize(value); + } - void swap(hashtable &rhs) noexcept; + pair insert_unique(value_type&& value) { + return emplace_unique(mystl::move(value)); + } - // 查找相关操作 + // [note]: 同 emplace_hint + iterator + insert_multi_use_hint(const_iterator /*hint*/, const value_type& value) { + return insert_multi(value); + } - size_type count(const key_type &key) const; + iterator + insert_multi_use_hint(const_iterator /*hint*/, value_type&& value) { + return emplace_multi(mystl::move(value)); + } - iterator find(const key_type &key); - const_iterator find(const key_type &key) const; + iterator + insert_unique_use_hint(const_iterator /*hint*/, const value_type& value) { + return insert_unique(value).first; + } - pair equal_range_multi(const key_type &key); - pair - equal_range_multi(const key_type &key) const; + iterator + insert_unique_use_hint(const_iterator /*hint*/, value_type&& value) { + return emplace_unique(mystl::move(value)); + } - pair equal_range_unique(const key_type &key); - pair - equal_range_unique(const key_type &key) const; + template + void insert_multi(InputIter first, InputIter last) { + copy_insert_multi(first, last, iterator_category(first)); + } - // bucket interface + template + void insert_unique(InputIter first, InputIter last) { + copy_insert_unique(first, last, iterator_category(first)); + } - local_iterator begin(size_type n) noexcept { - MYSTL_DEBUG(n < size_); - return buckets_[n]; - } - const_local_iterator begin(size_type n) const noexcept { - MYSTL_DEBUG(n < size_); - return buckets_[n]; - } - const_local_iterator cbegin(size_type n) const noexcept { - MYSTL_DEBUG(n < size_); - return buckets_[n]; - } + // erase / clear - local_iterator end(size_type n) noexcept { - MYSTL_DEBUG(n < size_); - return nullptr; - } - const_local_iterator end(size_type n) const noexcept { - MYSTL_DEBUG(n < size_); - return nullptr; - } - const_local_iterator cend(size_type n) const noexcept { - MYSTL_DEBUG(n < size_); - return nullptr; - } + void erase(const_iterator position); + void erase(const_iterator first, const_iterator last); - size_type bucket_count() const noexcept { - return bucket_size_; - } - size_type max_bucket_count() const noexcept { - return ht_prime_list[PRIME_NUM - 1]; - } + size_type erase_multi(const key_type& key); + size_type erase_unique(const key_type& key); - size_type bucket_size(size_type n) const noexcept; - size_type bucket(const key_type &key) const { - return hash(key); - } + void clear(); - // hash policy + void swap(hashtable& rhs) noexcept; - float load_factor() const noexcept { - return bucket_size_ != 0 ? (float)size_ / bucket_size_ : 0.0f; - } + // 查找相关操作 - float max_load_factor() const noexcept { - return mlf_; - } - void max_load_factor(float ml) { - THROW_OUT_OF_RANGE_IF(ml != ml || ml < 0, - "invalid hash load factor"); - mlf_ = ml; - } + size_type count(const key_type& key) const; - void rehash(size_type count); + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; - void reserve(size_type count) { - rehash(static_cast((float)count / max_load_factor() + - 0.5f)); - } + pair equal_range_multi(const key_type& key); + pair + equal_range_multi(const key_type& key) const; - hasher hash_fcn() const { - return hash_; - } - key_equal key_eq() const { - return equal_; - } + pair equal_range_unique(const key_type& key); + pair + equal_range_unique(const key_type& key) const; - private: - // hashtable 成员函数 - - // init - void init(size_type n); - void copy_init(const hashtable &ht); - - // node - template - node_ptr create_node(Args &&...args); - void destroy_node(node_ptr n); - - // hash - size_type next_size(size_type n) const; - size_type hash(const key_type &key, size_type n) const; - size_type hash(const key_type &key) const; - void rehash_if_need(size_type n); - - // insert - template - void copy_insert_multi(InputIter first, InputIter last, - mystl::input_iterator_tag); - template - void copy_insert_multi(ForwardIter first, ForwardIter last, - mystl::forward_iterator_tag); - template - void copy_insert_unique(InputIter first, InputIter last, - mystl::input_iterator_tag); - template - void copy_insert_unique(ForwardIter first, ForwardIter last, - mystl::forward_iterator_tag); - - // insert node - pair insert_node_unique(node_ptr np); - iterator insert_node_multi(node_ptr np); - - // bucket operator - void replace_bucket(size_type bucket_count); - void erase_bucket(size_type n, node_ptr first, node_ptr last); - void erase_bucket(size_type n, node_ptr last); - - // comparision - bool equal_to_multi(const hashtable &other); - bool equal_to_unique(const hashtable &other); - }; - - /*****************************************************************************************/ - - // 复制赋值运算符 - template - hashtable & - hashtable::operator=(const hashtable &rhs) { - if (this != &rhs) { - hashtable tmp(rhs); - swap(tmp); - } - return *this; + // bucket interface + + local_iterator begin(size_type n) noexcept { + MYSTL_DEBUG(n < size_); + return buckets_[n]; } - // 移动赋值运算符 - template - hashtable & - hashtable::operator=(hashtable &&rhs) noexcept { - hashtable tmp(mystl::move(rhs)); - swap(tmp); - return *this; + const_local_iterator begin(size_type n) const noexcept { + MYSTL_DEBUG(n < size_); + return buckets_[n]; } - // 就地构造元素,键值允许重复 - // 强异常安全保证 - template - template - typename hashtable::iterator - hashtable::emplace_multi(Args &&...args) { - auto np = create_node(mystl::forward(args)...); - try { - if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor()) - rehash(size_ + 1); - } catch (...) { - destroy_node(np); - throw; - } - return insert_node_multi(np); + const_local_iterator cbegin(size_type n) const noexcept { + MYSTL_DEBUG(n < size_); + return buckets_[n]; + } + + local_iterator end(size_type n) noexcept { + MYSTL_DEBUG(n < size_); + return nullptr; + } + + const_local_iterator end(size_type n) const noexcept { + MYSTL_DEBUG(n < size_); + return nullptr; + } + + const_local_iterator cend(size_type n) const noexcept { + MYSTL_DEBUG(n < size_); + return nullptr; } - // 就地构造元素,键值允许重复 - // 强异常安全保证 - template + size_type bucket_count() const noexcept { + return bucket_size_; + } + + size_type max_bucket_count() const noexcept { + return ht_prime_list[PRIME_NUM - 1]; + } + + size_type bucket_size(size_type n) const noexcept; + + size_type bucket(const key_type& key) const { + return hash(key); + } + + // hash policy + + float load_factor() const noexcept { + return bucket_size_ != 0 ? (float)size_ / bucket_size_ : 0.0f; + } + + float max_load_factor() const noexcept { + return mlf_; + } + + void max_load_factor(float ml) { + THROW_OUT_OF_RANGE_IF(ml != ml || ml < 0, "invalid hash load factor"); + mlf_ = ml; + } + + void rehash(size_type count); + + void reserve(size_type count) { + rehash(static_cast((float)count / max_load_factor() + 0.5f)); + } + + hasher hash_fcn() const { + return hash_; + } + + key_equal key_eq() const { + return equal_; + } + +private: + // hashtable 成员函数 + + // init + void init(size_type n); + void copy_init(const hashtable& ht); + + // node template - pair::iterator, bool> - hashtable::emplace_unique(Args &&...args) { - auto np = create_node(mystl::forward(args)...); - try { - if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor()) - rehash(size_ + 1); - } catch (...) { - destroy_node(np); - throw; + node_ptr create_node(Args&&... args); + void destroy_node(node_ptr n); + + // hash + size_type next_size(size_type n) const; + size_type hash(const key_type& key, size_type n) const; + size_type hash(const key_type& key) const; + void rehash_if_need(size_type n); + + // insert + template + void copy_insert_multi(InputIter first, InputIter last, + mystl::input_iterator_tag); + template + void copy_insert_multi(ForwardIter first, ForwardIter last, + mystl::forward_iterator_tag); + template + void copy_insert_unique(InputIter first, InputIter last, + mystl::input_iterator_tag); + template + void copy_insert_unique(ForwardIter first, ForwardIter last, + mystl::forward_iterator_tag); + + // insert node + pair insert_node_unique(node_ptr np); + iterator insert_node_multi(node_ptr np); + + // bucket operator + void replace_bucket(size_type bucket_count); + void erase_bucket(size_type n, node_ptr first, node_ptr last); + void erase_bucket(size_type n, node_ptr last); + + // comparision + bool equal_to_multi(const hashtable& other); + bool equal_to_unique(const hashtable& other); +}; + +/*****************************************************************************************/ + +// 复制赋值运算符 +template +hashtable& +hashtable::operator=(const hashtable& rhs) { + if (this != &rhs) { + hashtable tmp(rhs); + swap(tmp); + } + return *this; +} + +// 移动赋值运算符 +template +hashtable& +hashtable::operator=(hashtable&& rhs) noexcept { + hashtable tmp(mystl::move(rhs)); + swap(tmp); + return *this; +} + +// 就地构造元素,键值允许重复 +// 强异常安全保证 +template +template +typename hashtable::iterator +hashtable::emplace_multi(Args&&... args) { + auto np = create_node(mystl::forward(args)...); + try { + if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor()) { + rehash(size_ + 1); + } + } catch (...) { + destroy_node(np); + throw; + } + return insert_node_multi(np); +} + +// 就地构造元素,键值允许重复 +// 强异常安全保证 +template +template +pair::iterator, bool> +hashtable::emplace_unique(Args&&... args) { + auto np = create_node(mystl::forward(args)...); + try { + if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor()) { + rehash(size_ + 1); + } + } catch (...) { + destroy_node(np); + throw; + } + return insert_node_unique(np); +} + +// 在不需要重建表格的情况下插入新节点,键值不允许重复 +template +pair::iterator, bool> +hashtable::insert_unique_noresize(const value_type& value) { + const auto n = hash(value_traits::get_key(value)); + auto first = buckets_[n]; + for (auto cur = first; cur; cur = cur->next) { + if (is_equal(value_traits::get_key(cur->value), + value_traits::get_key(value))) { + return mystl::make_pair(iterator(cur, this), false); } - return insert_node_unique(np); - } - - // 在不需要重建表格的情况下插入新节点,键值不允许重复 - template - pair::iterator, bool> - hashtable::insert_unique_noresize( - const value_type &value) { - const auto n = hash(value_traits::get_key(value)); - auto first = buckets_[n]; - for (auto cur = first; cur; cur = cur->next) { - if (is_equal(value_traits::get_key(cur->value), - value_traits::get_key(value))) - return mystl::make_pair(iterator(cur, this), false); + } + // 让新节点成为链表的第一个节点 + auto tmp = create_node(value); + tmp->next = first; + buckets_[n] = tmp; + ++size_; + return mystl::make_pair(iterator(tmp, this), true); +} + +// 在不需要重建表格的情况下插入新节点,键值允许重复 +template +typename hashtable::iterator +hashtable::insert_multi_noresize(const value_type& value) { + const auto n = hash(value_traits::get_key(value)); + auto first = buckets_[n]; + auto tmp = create_node(value); + for (auto cur = first; cur; cur = cur->next) { + if ( + is_equal( + value_traits::get_key(cur->value), + value_traits::get_key( + value))) { // 如果链表中存在相同键值的节点就马上插入,然后返回 + tmp->next = cur->next; + cur->next = tmp; + ++size_; + return iterator(tmp, this); } - // 让新节点成为链表的第一个节点 - auto tmp = create_node(value); - tmp->next = first; - buckets_[n] = tmp; - ++size_; - return mystl::make_pair(iterator(tmp, this), true); - } - - // 在不需要重建表格的情况下插入新节点,键值允许重复 - template - typename hashtable::iterator - hashtable::insert_multi_noresize( - const value_type &value) { - const auto n = hash(value_traits::get_key(value)); - auto first = buckets_[n]; - auto tmp = create_node(value); - for (auto cur = first; cur; cur = cur->next) { - if (is_equal( - value_traits::get_key(cur->value), - value_traits::get_key( - value))) { // 如果链表中存在相同键值的节点就马上插入,然后返回 - tmp->next = cur->next; - cur->next = tmp; - ++size_; - return iterator(tmp, this); - } + } + // 否则插入在链表头部 + tmp->next = first; + buckets_[n] = tmp; + ++size_; + return iterator(tmp, this); +} + +// 删除迭代器所指的节点 +template +void hashtable::erase(const_iterator position) { + auto p = position.node; + if (p) { + const auto n = hash(value_traits::get_key(p->value)); + auto cur = buckets_[n]; + if (cur == p) { // p 位于链表头部 + buckets_[n] = cur->next; + destroy_node(cur); + --size_; } - // 否则插入在链表头部 - tmp->next = first; - buckets_[n] = tmp; - ++size_; - return iterator(tmp, this); - } - - // 删除迭代器所指的节点 - template - void hashtable::erase(const_iterator position) { - auto p = position.node; - if (p) { - const auto n = hash(value_traits::get_key(p->value)); - auto cur = buckets_[n]; - if (cur == p) { // p 位于链表头部 - buckets_[n] = cur->next; - destroy_node(cur); - --size_; - } - else { - auto next = cur->next; - while (next) { - if (next == p) { - cur->next = next->next; - destroy_node(next); - --size_; - break; - } - else { - cur = next; - next = cur->next; - } + else { + auto next = cur->next; + while (next) { + if (next == p) { + cur->next = next->next; + destroy_node(next); + --size_; + break; + } + else { + cur = next; + next = cur->next; } } } } - - // 删除[first, last)内的节点 - template - void hashtable::erase(const_iterator first, - const_iterator last) { - if (first.node == last.node) - return; - auto first_bucket = first.node - ? hash(value_traits::get_key(first.node->value)) - : bucket_size_; - auto last_bucket = last.node - ? hash(value_traits::get_key(last.node->value)) - : bucket_size_; - if (first_bucket == last_bucket) { // 如果在 bucket 在同一个位置 - erase_bucket(first_bucket, first.node, last.node); - } - else { - erase_bucket(first_bucket, first.node, nullptr); - for (auto n = first_bucket + 1; n < last_bucket; ++n) { - if (buckets_[n] != nullptr) - erase_bucket(n, nullptr); - } - if (last_bucket != bucket_size_) { - erase_bucket(last_bucket, last.node); +} + +// 删除[first, last)内的节点 +template +void hashtable::erase(const_iterator first, + const_iterator last) { + if (first.node == last.node) { + return; + } + auto first_bucket = first.node + ? hash(value_traits::get_key(first.node->value)) + : bucket_size_; + auto last_bucket = last.node ? hash(value_traits::get_key(last.node->value)) + : bucket_size_; + if (first_bucket == last_bucket) { // 如果在 bucket 在同一个位置 + erase_bucket(first_bucket, first.node, last.node); + } + else { + erase_bucket(first_bucket, first.node, nullptr); + for (auto n = first_bucket + 1; n < last_bucket; ++n) { + if (buckets_[n] != nullptr) { + erase_bucket(n, nullptr); } } + if (last_bucket != bucket_size_) { + erase_bucket(last_bucket, last.node); + } } - - // 删除键值为 key 的节点 - template - typename hashtable::size_type - hashtable::erase_multi(const key_type &key) { - auto p = equal_range_multi(key); - if (p.first.node != nullptr) { - erase(p.first, p.second); - return mystl::distance(p.first, p.second); +} + +// 删除键值为 key 的节点 +template +typename hashtable::size_type +hashtable::erase_multi(const key_type& key) { + auto p = equal_range_multi(key); + if (p.first.node != nullptr) { + erase(p.first, p.second); + return mystl::distance(p.first, p.second); + } + return 0; +} + +template +typename hashtable::size_type +hashtable::erase_unique(const key_type& key) { + const auto n = hash(key); + auto first = buckets_[n]; + if (first) { + if (is_equal(value_traits::get_key(first->value), key)) { + buckets_[n] = first->next; + destroy_node(first); + --size_; + return 1; } - return 0; - } - - template - typename hashtable::size_type - hashtable::erase_unique(const key_type &key) { - const auto n = hash(key); - auto first = buckets_[n]; - if (first) { - if (is_equal(value_traits::get_key(first->value), key)) { - buckets_[n] = first->next; - destroy_node(first); - --size_; - return 1; - } - else { - auto next = first->next; - while (next) { - if (is_equal(value_traits::get_key(next->value), key)) { - first->next = next->next; - destroy_node(next); - --size_; - return 1; - } - first = next; - next = first->next; + else { + auto next = first->next; + while (next) { + if (is_equal(value_traits::get_key(next->value), key)) { + first->next = next->next; + destroy_node(next); + --size_; + return 1; } + first = next; + next = first->next; } } - return 0; - } - - // 清空 hashtable - template - void hashtable::clear() { - if (size_ != 0) { - for (size_type i = 0; i < bucket_size_; ++i) { - node_ptr cur = buckets_[i]; - while (cur != nullptr) { - node_ptr next = cur->next; - destroy_node(cur); - cur = next; - } - buckets_[i] = nullptr; + } + return 0; +} + +// 清空 hashtable +template +void hashtable::clear() { + if (size_ != 0) { + for (size_type i = 0; i < bucket_size_; ++i) { + node_ptr cur = buckets_[i]; + while (cur != nullptr) { + node_ptr next = cur->next; + destroy_node(cur); + cur = next; } - size_ = 0; + buckets_[i] = nullptr; } + size_ = 0; } - - // 在某个 bucket 节点的个数 - template - typename hashtable::size_type - hashtable::bucket_size(size_type n) const noexcept { - size_type result = 0; - for (auto cur = buckets_[n]; cur; cur = cur->next) { - ++result; - } - return result; +} + +// 在某个 bucket 节点的个数 +template +typename hashtable::size_type +hashtable::bucket_size(size_type n) const noexcept { + size_type result = 0; + for (auto cur = buckets_[n]; cur; cur = cur->next) { + ++result; } - - // 重新对元素进行一遍哈希,插入到新的位置 - template - void hashtable::rehash(size_type count) { - auto n = ht_next_prime(count); - if (n > bucket_size_) { + return result; +} + +// 重新对元素进行一遍哈希,插入到新的位置 +template +void hashtable::rehash(size_type count) { + auto n = ht_next_prime(count); + if (n > bucket_size_) { + replace_bucket(n); + } + else { + if ((float)size_ / (float)n < max_load_factor() - 0.25f + && (float)n < (float)bucket_size_ * 0.75) // worth rehash + { replace_bucket(n); } - else { - if ((float)size_ / (float)n < max_load_factor() - 0.25f && - (float)n < (float)bucket_size_ * 0.75) // worth rehash - { - replace_bucket(n); - } - } } - - // 查找键值为 key 的节点,返回其迭代器 - template - typename hashtable::iterator - hashtable::find(const key_type &key) { - const auto n = hash(key); - node_ptr first = buckets_[n]; - for (; first && !is_equal(value_traits::get_key(first->value), key); - first = first->next) {} - return iterator(first, this); - } - - template - typename hashtable::const_iterator - hashtable::find(const key_type &key) const { - const auto n = hash(key); - node_ptr first = buckets_[n]; - for (; first && !is_equal(value_traits::get_key(first->value), key); - first = first->next) {} - return M_cit(first); - } - - // 查找键值为 key 出现的次数 - template - typename hashtable::size_type - hashtable::count(const key_type &key) const { - const auto n = hash(key); - size_type result = 0; - for (node_ptr cur = buckets_[n]; cur; cur = cur->next) { - if (is_equal(value_traits::get_key(cur->value), key)) - ++result; +} + +// 查找键值为 key 的节点,返回其迭代器 +template +typename hashtable::iterator +hashtable::find(const key_type& key) { + const auto n = hash(key); + node_ptr first = buckets_[n]; + for (; first && !is_equal(value_traits::get_key(first->value), key); + first = first->next) { + } + return iterator(first, this); +} + +template +typename hashtable::const_iterator +hashtable::find(const key_type& key) const { + const auto n = hash(key); + node_ptr first = buckets_[n]; + for (; first && !is_equal(value_traits::get_key(first->value), key); + first = first->next) { + } + return M_cit(first); +} + +// 查找键值为 key 出现的次数 +template +typename hashtable::size_type +hashtable::count(const key_type& key) const { + const auto n = hash(key); + size_type result = 0; + for (node_ptr cur = buckets_[n]; cur; cur = cur->next) { + if (is_equal(value_traits::get_key(cur->value), key)) { + ++result; } - return result; - } - - // 查找与键值 key 相等的区间,返回一个 pair,指向相等区间的首尾 - template - pair::iterator, - typename hashtable::iterator> - hashtable::equal_range_multi(const key_type &key) { - const auto n = hash(key); - for (node_ptr first = buckets_[n]; first; first = first->next) { - if (is_equal(value_traits::get_key(first->value), - key)) { // 如果出现相等的键值 - for (node_ptr second = first->next; second; - second = second->next) { - if (!is_equal(value_traits::get_key(second->value), key)) - return mystl::make_pair(iterator(first, this), - iterator(second, this)); + } + return result; +} + +// 查找与键值 key 相等的区间,返回一个 pair,指向相等区间的首尾 +template +pair::iterator, + typename hashtable::iterator> +hashtable::equal_range_multi(const key_type& key) { + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) { + if (is_equal(value_traits::get_key(first->value), + key)) { // 如果出现相等的键值 + for (node_ptr second = first->next; second; second = second->next) { + if (!is_equal(value_traits::get_key(second->value), key)) { + return mystl::make_pair(iterator(first, this), + iterator(second, this)); } - for (auto m = n + 1; m < bucket_size_; - ++m) { // 整个链表都相等,查找下一个链表出现的位置 - if (buckets_[m]) - return mystl::make_pair(iterator(first, this), - iterator(buckets_[m], this)); + } + for (auto m = n + 1; m < bucket_size_; + ++m) { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) { + return mystl::make_pair(iterator(first, this), + iterator(buckets_[m], this)); } - return mystl::make_pair(iterator(first, this), end()); } + return mystl::make_pair(iterator(first, this), end()); } - return mystl::make_pair(end(), end()); - } - - template - pair::const_iterator, - typename hashtable::const_iterator> - hashtable::equal_range_multi(const key_type &key) const { - const auto n = hash(key); - for (node_ptr first = buckets_[n]; first; first = first->next) { - if (is_equal(value_traits::get_key(first->value), key)) { - for (node_ptr second = first->next; second; - second = second->next) { - if (!is_equal(value_traits::get_key(second->value), key)) - return mystl::make_pair(M_cit(first), M_cit(second)); + } + return mystl::make_pair(end(), end()); +} + +template +pair::const_iterator, + typename hashtable::const_iterator> +hashtable::equal_range_multi(const key_type& key) const { + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) { + if (is_equal(value_traits::get_key(first->value), key)) { + for (node_ptr second = first->next; second; second = second->next) { + if (!is_equal(value_traits::get_key(second->value), key)) { + return mystl::make_pair(M_cit(first), M_cit(second)); } - for (auto m = n + 1; m < bucket_size_; - ++m) { // 整个链表都相等,查找下一个链表出现的位置 - if (buckets_[m]) - return mystl::make_pair(M_cit(first), - M_cit(buckets_[m])); + } + for (auto m = n + 1; m < bucket_size_; + ++m) { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) { + return mystl::make_pair(M_cit(first), M_cit(buckets_[m])); } - return mystl::make_pair(M_cit(first), cend()); } + return mystl::make_pair(M_cit(first), cend()); } - return mystl::make_pair(cend(), cend()); } - - template - pair::iterator, - typename hashtable::iterator> - hashtable::equal_range_unique(const key_type &key) { - const auto n = hash(key); - for (node_ptr first = buckets_[n]; first; first = first->next) { - if (is_equal(value_traits::get_key(first->value), key)) { - if (first->next) + return mystl::make_pair(cend(), cend()); +} + +template +pair::iterator, + typename hashtable::iterator> +hashtable::equal_range_unique(const key_type& key) { + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) { + if (is_equal(value_traits::get_key(first->value), key)) { + if (first->next) { + return mystl::make_pair(iterator(first, this), + iterator(first->next, this)); + } + for (auto m = n + 1; m < bucket_size_; + ++m) { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) { return mystl::make_pair(iterator(first, this), - iterator(first->next, this)); - for (auto m = n + 1; m < bucket_size_; - ++m) { // 整个链表都相等,查找下一个链表出现的位置 - if (buckets_[m]) - return mystl::make_pair(iterator(first, this), - iterator(buckets_[m], this)); + iterator(buckets_[m], this)); } - return mystl::make_pair(iterator(first, this), end()); } + return mystl::make_pair(iterator(first, this), end()); } - return mystl::make_pair(end(), end()); - } - - template - pair::const_iterator, - typename hashtable::const_iterator> - hashtable::equal_range_unique( - const key_type &key) const { - const auto n = hash(key); - for (node_ptr first = buckets_[n]; first; first = first->next) { - if (is_equal(value_traits::get_key(first->value), key)) { - if (first->next) - return mystl::make_pair(M_cit(first), M_cit(first->next)); - for (auto m = n + 1; m < bucket_size_; - ++m) { // 整个链表都相等,查找下一个链表出现的位置 - if (buckets_[m]) - return mystl::make_pair(M_cit(first), - M_cit(buckets_[m])); + } + return mystl::make_pair(end(), end()); +} + +template +pair::const_iterator, + typename hashtable::const_iterator> +hashtable::equal_range_unique(const key_type& key) const { + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) { + if (is_equal(value_traits::get_key(first->value), key)) { + if (first->next) { + return mystl::make_pair(M_cit(first), M_cit(first->next)); + } + for (auto m = n + 1; m < bucket_size_; + ++m) { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) { + return mystl::make_pair(M_cit(first), M_cit(buckets_[m])); } - return mystl::make_pair(M_cit(first), cend()); } + return mystl::make_pair(M_cit(first), cend()); } - return mystl::make_pair(cend(), cend()); } - - // 交换 hashtable - template - void hashtable::swap(hashtable &rhs) noexcept { - if (this != &rhs) { - buckets_.swap(rhs.buckets_); - mystl::swap(bucket_size_, rhs.bucket_size_); - mystl::swap(size_, rhs.size_); - mystl::swap(mlf_, rhs.mlf_); - mystl::swap(hash_, rhs.hash_); - mystl::swap(equal_, rhs.equal_); - } + return mystl::make_pair(cend(), cend()); +} + +// 交换 hashtable +template +void hashtable::swap(hashtable& rhs) noexcept { + if (this != &rhs) { + buckets_.swap(rhs.buckets_); + mystl::swap(bucket_size_, rhs.bucket_size_); + mystl::swap(size_, rhs.size_); + mystl::swap(mlf_, rhs.mlf_); + mystl::swap(hash_, rhs.hash_); + mystl::swap(equal_, rhs.equal_); } - - /****************************************************************************************/ - // helper function - - // init 函数 - template - void hashtable::init(size_type n) { - const auto bucket_nums = next_size(n); - try { - buckets_.reserve(bucket_nums); - buckets_.assign(bucket_nums, nullptr); - } catch (...) { - bucket_size_ = 0; - size_ = 0; - throw; - } - bucket_size_ = buckets_.size(); - } - - // copy_init 函数 - template - void hashtable::copy_init(const hashtable &ht) { +} + +/****************************************************************************************/ +// helper function + +// init 函数 +template +void hashtable::init(size_type n) { + const auto bucket_nums = next_size(n); + try { + buckets_.reserve(bucket_nums); + buckets_.assign(bucket_nums, nullptr); + } catch (...) { bucket_size_ = 0; - buckets_.reserve(ht.bucket_size_); - buckets_.assign(ht.bucket_size_, nullptr); - try { - for (size_type i = 0; i < ht.bucket_size_; ++i) { - node_ptr cur = ht.buckets_[i]; - if (cur) { // 如果某 bucket 存在链表 - auto copy = create_node(cur->value); - buckets_[i] = copy; - for (auto next = cur->next; next; - cur = next, next = cur->next) { //复制链表 - copy->next = create_node(next->value); - copy = copy->next; - } - copy->next = nullptr; + size_ = 0; + throw; + } + bucket_size_ = buckets_.size(); +} + +// copy_init 函数 +template +void hashtable::copy_init(const hashtable& ht) { + bucket_size_ = 0; + buckets_.reserve(ht.bucket_size_); + buckets_.assign(ht.bucket_size_, nullptr); + try { + for (size_type i = 0; i < ht.bucket_size_; ++i) { + node_ptr cur = ht.buckets_[i]; + if (cur) { // 如果某 bucket 存在链表 + auto copy = create_node(cur->value); + buckets_[i] = copy; + for (auto next = cur->next; next; + cur = next, next = cur->next) { // 复制链表 + copy->next = create_node(next->value); + copy = copy->next; } + copy->next = nullptr; } - bucket_size_ = ht.bucket_size_; - mlf_ = ht.mlf_; - size_ = ht.size_; - } catch (...) { clear(); } - } - - // create_node 函数 - template - template - typename hashtable::node_ptr - hashtable::create_node(Args &&...args) { - node_ptr tmp = node_allocator::allocate(1); - try { - data_allocator::construct(mystl::address_of(tmp->value), - mystl::forward(args)...); - tmp->next = nullptr; - } catch (...) { - node_allocator::deallocate(tmp); - throw; } - return tmp; + bucket_size_ = ht.bucket_size_; + mlf_ = ht.mlf_; + size_ = ht.size_; + } catch (...) { + clear(); } - - // destroy_node 函数 - template - void hashtable::destroy_node(node_ptr node) { - data_allocator::destroy(mystl::address_of(node->value)); - node_allocator::deallocate(node); - node = nullptr; +} + +// create_node 函数 +template +template +typename hashtable::node_ptr +hashtable::create_node(Args&&... args) { + node_ptr tmp = node_allocator::allocate(1); + try { + data_allocator::construct(mystl::address_of(tmp->value), + mystl::forward(args)...); + tmp->next = nullptr; + } catch (...) { + node_allocator::deallocate(tmp); + throw; } - - // next_size 函数 - template - typename hashtable::size_type - hashtable::next_size(size_type n) const { - return ht_next_prime(n); + return tmp; +} + +// destroy_node 函数 +template +void hashtable::destroy_node(node_ptr node) { + data_allocator::destroy(mystl::address_of(node->value)); + node_allocator::deallocate(node); + node = nullptr; +} + +// next_size 函数 +template +typename hashtable::size_type +hashtable::next_size(size_type n) const { + return ht_next_prime(n); +} + +// hash 函数 +template +typename hashtable::size_type +hashtable::hash(const key_type& key, size_type n) const { + return hash_(key) % n; +} + +template +typename hashtable::size_type +hashtable::hash(const key_type& key) const { + return hash_(key) % bucket_size_; +} + +// rehash_if_need 函数 +template +void hashtable::rehash_if_need(size_type n) { + if (static_cast(size_ + n) + > (float)bucket_size_ * max_load_factor()) { + rehash(size_ + n); } - - // hash 函数 - template - typename hashtable::size_type - hashtable::hash(const key_type &key, size_type n) const { - return hash_(key) % n; +} + +// copy_insert +template +template +void hashtable::copy_insert_multi( + InputIter first, InputIter last, mystl::input_iterator_tag) { + rehash_if_need(mystl::distance(first, last)); + for (; first != last; ++first) { + insert_multi_noresize(*first); } - - template - typename hashtable::size_type - hashtable::hash(const key_type &key) const { - return hash_(key) % bucket_size_; - } - - // rehash_if_need 函数 - template - void hashtable::rehash_if_need(size_type n) { - if (static_cast(size_ + n) > - (float)bucket_size_ * max_load_factor()) - rehash(size_ + n); - } - - // copy_insert - template - template - void hashtable::copy_insert_multi( - InputIter first, InputIter last, mystl::input_iterator_tag) { - rehash_if_need(mystl::distance(first, last)); - for (; first != last; ++first) - insert_multi_noresize(*first); +} + +template +template +void hashtable::copy_insert_multi( + ForwardIter first, ForwardIter last, mystl::forward_iterator_tag) { + size_type n = mystl::distance(first, last); + rehash_if_need(n); + for (; n > 0; --n, ++first) { + insert_multi_noresize(*first); } - - template - template - void hashtable::copy_insert_multi( - ForwardIter first, ForwardIter last, mystl::forward_iterator_tag) { - size_type n = mystl::distance(first, last); - rehash_if_need(n); - for (; n > 0; --n, ++first) - insert_multi_noresize(*first); +} + +template +template +void hashtable::copy_insert_unique( + InputIter first, InputIter last, mystl::input_iterator_tag) { + rehash_if_need(mystl::distance(first, last)); + for (; first != last; ++first) { + insert_unique_noresize(*first); } - - template - template - void hashtable::copy_insert_unique( - InputIter first, InputIter last, mystl::input_iterator_tag) { - rehash_if_need(mystl::distance(first, last)); - for (; first != last; ++first) - insert_unique_noresize(*first); +} + +template +template +void hashtable::copy_insert_unique( + ForwardIter first, ForwardIter last, mystl::forward_iterator_tag) { + size_type n = mystl::distance(first, last); + rehash_if_need(n); + for (; n > 0; --n, ++first) { + insert_unique_noresize(*first); } - - template - template - void hashtable::copy_insert_unique( - ForwardIter first, ForwardIter last, mystl::forward_iterator_tag) { - size_type n = mystl::distance(first, last); - rehash_if_need(n); - for (; n > 0; --n, ++first) - insert_unique_noresize(*first); - } - - // insert_node 函数 - template - typename hashtable::iterator - hashtable::insert_node_multi(node_ptr np) { - const auto n = hash(value_traits::get_key(np->value)); - auto cur = buckets_[n]; - if (cur == nullptr) { - buckets_[n] = np; - ++size_; - return iterator(np, this); - } - for (; cur; cur = cur->next) { - if (is_equal(value_traits::get_key(cur->value), - value_traits::get_key(np->value))) { - np->next = cur->next; - cur->next = np; - ++size_; - return iterator(np, this); - } - } - np->next = buckets_[n]; +} + +// insert_node 函数 +template +typename hashtable::iterator +hashtable::insert_node_multi(node_ptr np) { + const auto n = hash(value_traits::get_key(np->value)); + auto cur = buckets_[n]; + if (cur == nullptr) { buckets_[n] = np; ++size_; return iterator(np, this); } - - // insert_node_unique 函数 - template - pair::iterator, bool> - hashtable::insert_node_unique(node_ptr np) { - const auto n = hash(value_traits::get_key(np->value)); - auto cur = buckets_[n]; - if (cur == nullptr) { - buckets_[n] = np; + for (; cur; cur = cur->next) { + if (is_equal(value_traits::get_key(cur->value), + value_traits::get_key(np->value))) { + np->next = cur->next; + cur->next = np; ++size_; - return mystl::make_pair(iterator(np, this), true); - } - for (; cur; cur = cur->next) { - if (is_equal(value_traits::get_key(cur->value), - value_traits::get_key(np->value))) { - return mystl::make_pair(iterator(cur, this), false); - } + return iterator(np, this); } - np->next = buckets_[n]; + } + np->next = buckets_[n]; + buckets_[n] = np; + ++size_; + return iterator(np, this); +} + +// insert_node_unique 函数 +template +pair::iterator, bool> +hashtable::insert_node_unique(node_ptr np) { + const auto n = hash(value_traits::get_key(np->value)); + auto cur = buckets_[n]; + if (cur == nullptr) { buckets_[n] = np; ++size_; return mystl::make_pair(iterator(np, this), true); } - - // replace_bucket 函数 - template - void hashtable::replace_bucket(size_type bucket_count) { - bucket_type bucket(bucket_count); - if (size_ != 0) { - for (size_type i = 0; i < bucket_size_; ++i) { - for (auto first = buckets_[i]; first; first = first->next) { - auto tmp = create_node(first->value); - const auto n = - hash(value_traits::get_key(first->value), bucket_count); - auto f = bucket[n]; - bool is_inserted = false; - for (auto cur = f; cur; cur = cur->next) { - if (is_equal(value_traits::get_key(cur->value), - value_traits::get_key(first->value))) { - tmp->next = cur->next; - cur->next = tmp; - is_inserted = true; - break; - } - } - if (!is_inserted) { - tmp->next = f; - bucket[n] = tmp; + for (; cur; cur = cur->next) { + if (is_equal(value_traits::get_key(cur->value), + value_traits::get_key(np->value))) { + return mystl::make_pair(iterator(cur, this), false); + } + } + np->next = buckets_[n]; + buckets_[n] = np; + ++size_; + return mystl::make_pair(iterator(np, this), true); +} + +// replace_bucket 函数 +template +void hashtable::replace_bucket(size_type bucket_count) { + bucket_type bucket(bucket_count); + if (size_ != 0) { + for (size_type i = 0; i < bucket_size_; ++i) { + for (auto first = buckets_[i]; first; first = first->next) { + auto tmp = create_node(first->value); + const auto n + = hash(value_traits::get_key(first->value), bucket_count); + auto f = bucket[n]; + bool is_inserted = false; + for (auto cur = f; cur; cur = cur->next) { + if (is_equal(value_traits::get_key(cur->value), + value_traits::get_key(first->value))) { + tmp->next = cur->next; + cur->next = tmp; + is_inserted = true; + break; } } - } - } - buckets_.swap(bucket); - bucket_size_ = buckets_.size(); - } - - // erase_bucket 函数 - // 在第 n 个 bucket 内,删除 [first, last) 的节点 - template - void hashtable::erase_bucket(size_type n, node_ptr first, - node_ptr last) { - auto cur = buckets_[n]; - if (cur == first) { - erase_bucket(n, last); - } - else { - node_ptr next = cur->next; - for (; next != first; cur = next, next = cur->next) {} - while (next != last) { - cur->next = next->next; - destroy_node(next); - next = cur->next; - --size_; + if (!is_inserted) { + tmp->next = f; + bucket[n] = tmp; + } } } } - - // erase_bucket 函数 - // 在第 n 个 bucket 内,删除 [buckets_[n], last) 的节点 - template - void hashtable::erase_bucket(size_type n, - node_ptr last) { - auto cur = buckets_[n]; - while (cur != last) { - auto next = cur->next; - destroy_node(cur); - cur = next; + buckets_.swap(bucket); + bucket_size_ = buckets_.size(); +} + +// erase_bucket 函数 +// 在第 n 个 bucket 内,删除 [first, last) 的节点 +template +void hashtable::erase_bucket(size_type n, node_ptr first, + node_ptr last) { + auto cur = buckets_[n]; + if (cur == first) { + erase_bucket(n, last); + } + else { + node_ptr next = cur->next; + for (; next != first; cur = next, next = cur->next) { + } + while (next != last) { + cur->next = next->next; + destroy_node(next); + next = cur->next; --size_; } - buckets_[n] = last; } - - // equal_to 函数 - template - bool hashtable::equal_to_multi(const hashtable &other) { - if (size_ != other.size_) +} + +// erase_bucket 函数 +// 在第 n 个 bucket 内,删除 [buckets_[n], last) 的节点 +template +void hashtable::erase_bucket(size_type n, node_ptr last) { + auto cur = buckets_[n]; + while (cur != last) { + auto next = cur->next; + destroy_node(cur); + cur = next; + --size_; + } + buckets_[n] = last; +} + +// equal_to 函数 +template +bool hashtable::equal_to_multi(const hashtable& other) { + if (size_ != other.size_) { + return false; + } + for (auto f = begin(), l = end(); f != l;) { + auto p1 = equal_range_multi(value_traits::get_key(*f)); + auto p2 = other.equal_range_multi(value_traits::get_key(*f)); + if (mystl::distance(p1.first, p1.last) + != mystl::distance(p2.first, p2.last) + || !mystl::is_permutation(p1.first, p2.last, p2.first, p2.last)) { return false; - for (auto f = begin(), l = end(); f != l;) { - auto p1 = equal_range_multi(value_traits::get_key(*f)); - auto p2 = other.equal_range_multi(value_traits::get_key(*f)); - if (mystl::distance(p1.first, p1.last) != - mystl::distance(p2.first, p2.last) || - !mystl::is_permutation(p1.first, p2.last, p2.first, p2.last)) - return false; - f = p1.last; } - return true; + f = p1.last; } + return true; +} - template - bool hashtable::equal_to_unique(const hashtable &other) { - if (size_ != other.size_) +template +bool hashtable::equal_to_unique(const hashtable& other) { + if (size_ != other.size_) { + return false; + } + for (auto f = begin(), l = end(); f != l; ++f) { + auto res = other.find(value_traits::get_key(*f)); + if (res.node == nullptr || *res != *f) { return false; - for (auto f = begin(), l = end(); f != l; ++f) { - auto res = other.find(value_traits::get_key(*f)); - if (res.node == nullptr || *res != *f) - return false; } - return true; } + return true; +} - // 重载 mystl 的 swap - template - void swap(hashtable &lhs, - hashtable &rhs) noexcept { - lhs.swap(rhs); - } +// 重载 mystl 的 swap +template +void swap(hashtable& lhs, + hashtable& rhs) noexcept { + lhs.swap(rhs); +} -}; +}; // namespace mystl -#endif /* _HASHTABLE_ */ +#endif /* SIMPLEKERNEL_HASHTABLE */ diff --git a/src/libcxx/include/heap_algo b/src/libcxx/include/heap_algo index 826b8848c..ed9bdbb1c 100644 --- a/src/libcxx/include/heap_algo +++ b/src/libcxx/include/heap_algo @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// heap_algo for Simple-XX/SimpleKernel. - -#ifndef _HEAP_ALGO_ -#define _HEAP_ALGO_ +/** + * @file heap_algo + * @brief stl heap_algo 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_HEAP_ALGO +#define SIMPLEKERNEL_HEAP_ALGO // 这个头文件包含 heap 的四个算法 : push_heap, pop_heap, sort_heap, make_heap @@ -13,208 +24,210 @@ namespace mystl { - /*****************************************************************************************/ - // push_heap - // 该函数接受两个迭代器,表示一个 heap - // 容器的首尾,并且新元素已经插入到底部容器的最尾端,调整 heap - /*****************************************************************************************/ - template - void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, - T value) { - auto parent = (holeIndex - 1) / 2; - while (holeIndex > topIndex && *(first + parent) < value) { - // 使用 operator<,所以 heap 为 max-heap - *(first + holeIndex) = *(first + parent); - holeIndex = parent; - parent = (holeIndex - 1) / 2; - } - *(first + holeIndex) = value; - } - - template - void push_heap_d(RandomIter first, RandomIter last, Distance *) { - mystl::push_heap_aux(first, (last - first) - 1, - static_cast(0), *(last - 1)); - } - - template - void push_heap(RandomIter first, - RandomIter last) { // 新元素应该已置于底部容器的最尾端 - mystl::push_heap_d(first, last, distance_type(first)); - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, - T value, Compared comp) { - auto parent = (holeIndex - 1) / 2; - while (holeIndex > topIndex && comp(*(first + parent), value)) { - *(first + holeIndex) = *(first + parent); - holeIndex = parent; - parent = (holeIndex - 1) / 2; - } - *(first + holeIndex) = value; - } - - template - void push_heap_d(RandomIter first, RandomIter last, Distance *, - Compared comp) { - mystl::push_heap_aux(first, (last - first) - 1, - static_cast(0), *(last - 1), comp); - } - - template - void push_heap(RandomIter first, RandomIter last, Compared comp) { - mystl::push_heap_d(first, last, distance_type(first), comp); - } - - /*****************************************************************************************/ - // pop_heap - // 该函数接受两个迭代器,表示 heap 容器的首尾,将 heap - // 的根节点取出放到容器尾部,调整 heap - /*****************************************************************************************/ - template - void adjust_heap(RandomIter first, Distance holeIndex, Distance len, - T value) { - // 先进行下溯(percolate down)过程 - auto topIndex = holeIndex; - auto rchild = 2 * holeIndex + 2; - while (rchild < len) { - if (*(first + rchild) < *(first + rchild - 1)) - --rchild; - *(first + holeIndex) = *(first + rchild); - holeIndex = rchild; - rchild = 2 * (rchild + 1); - } - if (rchild == len) { // 如果没有右子节点 - *(first + holeIndex) = *(first + (rchild - 1)); - holeIndex = rchild - 1; - } - // 再执行一次上溯(percolate up)过程 - mystl::push_heap_aux(first, holeIndex, topIndex, value); - } - - template - void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, - T value, Distance *) { - // 先将首值调至尾节点,然后调整[first, last - 1)使之重新成为一个 - // max-heap - *result = *first; - mystl::adjust_heap(first, static_cast(0), last - first, - value); - } - - template - void pop_heap(RandomIter first, RandomIter last) { - mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), - distance_type(first)); - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - void adjust_heap(RandomIter first, Distance holeIndex, Distance len, - T value, Compared comp) { - // 先进行下溯(percolate down)过程 - auto topIndex = holeIndex; - auto rchild = 2 * holeIndex + 2; - while (rchild < len) { - if (comp(*(first + rchild), *(first + rchild - 1))) - --rchild; - *(first + holeIndex) = *(first + rchild); - holeIndex = rchild; - rchild = 2 * (rchild + 1); - } - if (rchild == len) { - *(first + holeIndex) = *(first + (rchild - 1)); - holeIndex = rchild - 1; - } - // 再执行一次上溯(percolate up)过程 - mystl::push_heap_aux(first, holeIndex, topIndex, value, comp); - } - - template - void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, - T value, Distance *, Compared comp) { - *result = *first; // 先将尾指设置成首值,即尾指为欲求结果 - mystl::adjust_heap(first, static_cast(0), last - first, value, - comp); - } - - template - void pop_heap(RandomIter first, RandomIter last, Compared comp) { - mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), - distance_type(first), comp); - } - - /*****************************************************************************************/ - // sort_heap - // 该函数接受两个迭代器,表示 heap 容器的首尾,不断执行 pop_heap - // 操作,直到首尾最多相差1 - /*****************************************************************************************/ - template - void sort_heap(RandomIter first, RandomIter last) { - // 每执行一次 - // pop_heap,最大的元素都被放到尾部,直到容器最多只有一个元素,完成排序 - while (last - first > 1) { - mystl::pop_heap(first, last--); +/*****************************************************************************************/ +// push_heap +// 该函数接受两个迭代器,表示一个 heap +// 容器的首尾,并且新元素已经插入到底部容器的最尾端,调整 heap +/*****************************************************************************************/ +template +void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, + T value) { + auto parent = (holeIndex - 1) / 2; + while (holeIndex > topIndex && *(first + parent) < value) { + // 使用 operator<,所以 heap 为 max-heap + *(first + holeIndex) = *(first + parent); + holeIndex = parent; + parent = (holeIndex - 1) / 2; + } + *(first + holeIndex) = value; +} + +template +void push_heap_d(RandomIter first, RandomIter last, Distance*) { + mystl::push_heap_aux(first, (last - first) - 1, static_cast(0), + *(last - 1)); +} + +template +void push_heap(RandomIter first, + RandomIter last) { // 新元素应该已置于底部容器的最尾端 + mystl::push_heap_d(first, last, distance_type(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, + T value, Compared comp) { + auto parent = (holeIndex - 1) / 2; + while (holeIndex > topIndex && comp(*(first + parent), value)) { + *(first + holeIndex) = *(first + parent); + holeIndex = parent; + parent = (holeIndex - 1) / 2; + } + *(first + holeIndex) = value; +} + +template +void push_heap_d(RandomIter first, RandomIter last, Distance*, Compared comp) { + mystl::push_heap_aux(first, (last - first) - 1, static_cast(0), + *(last - 1), comp); +} + +template +void push_heap(RandomIter first, RandomIter last, Compared comp) { + mystl::push_heap_d(first, last, distance_type(first), comp); +} + +/*****************************************************************************************/ +// pop_heap +// 该函数接受两个迭代器,表示 heap 容器的首尾,将 heap +// 的根节点取出放到容器尾部,调整 heap +/*****************************************************************************************/ +template +void adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value) { + // 先进行下溯(percolate down)过程 + auto topIndex = holeIndex; + auto rchild = 2 * holeIndex + 2; + while (rchild < len) { + if (*(first + rchild) < *(first + rchild - 1)) { + --rchild; } - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - void sort_heap(RandomIter first, RandomIter last, Compared comp) { - while (last - first > 1) { - mystl::pop_heap(first, last--, comp); + *(first + holeIndex) = *(first + rchild); + holeIndex = rchild; + rchild = 2 * (rchild + 1); + } + if (rchild == len) { // 如果没有右子节点 + *(first + holeIndex) = *(first + (rchild - 1)); + holeIndex = rchild - 1; + } + // 再执行一次上溯(percolate up)过程 + mystl::push_heap_aux(first, holeIndex, topIndex, value); +} + +template +void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, T value, + Distance*) { + // 先将首值调至尾节点,然后调整[first, last - 1)使之重新成为一个 + // max-heap + *result = *first; + mystl::adjust_heap(first, static_cast(0), last - first, value); +} + +template +void pop_heap(RandomIter first, RandomIter last) { + mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), + distance_type(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value, + Compared comp) { + // 先进行下溯(percolate down)过程 + auto topIndex = holeIndex; + auto rchild = 2 * holeIndex + 2; + while (rchild < len) { + if (comp(*(first + rchild), *(first + rchild - 1))) { + --rchild; } - } - - /*****************************************************************************************/ - // make_heap - // 该函数接受两个迭代器,表示 heap 容器的首尾,把容器内的数据变为一个 heap - /*****************************************************************************************/ - template - void make_heap_aux(RandomIter first, RandomIter last, Distance *) { - if (last - first < 2) + *(first + holeIndex) = *(first + rchild); + holeIndex = rchild; + rchild = 2 * (rchild + 1); + } + if (rchild == len) { + *(first + holeIndex) = *(first + (rchild - 1)); + holeIndex = rchild - 1; + } + // 再执行一次上溯(percolate up)过程 + mystl::push_heap_aux(first, holeIndex, topIndex, value, comp); +} + +template +void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, T value, + Distance*, Compared comp) { + *result = *first; // 先将尾指设置成首值,即尾指为欲求结果 + mystl::adjust_heap(first, static_cast(0), last - first, value, + comp); +} + +template +void pop_heap(RandomIter first, RandomIter last, Compared comp) { + mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), + distance_type(first), comp); +} + +/*****************************************************************************************/ +// sort_heap +// 该函数接受两个迭代器,表示 heap 容器的首尾,不断执行 pop_heap +// 操作,直到首尾最多相差1 +/*****************************************************************************************/ +template +void sort_heap(RandomIter first, RandomIter last) { + // 每执行一次 + // pop_heap,最大的元素都被放到尾部,直到容器最多只有一个元素,完成排序 + while (last - first > 1) { + mystl::pop_heap(first, last--); + } +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void sort_heap(RandomIter first, RandomIter last, Compared comp) { + while (last - first > 1) { + mystl::pop_heap(first, last--, comp); + } +} + +/*****************************************************************************************/ +// make_heap +// 该函数接受两个迭代器,表示 heap 容器的首尾,把容器内的数据变为一个 heap +/*****************************************************************************************/ +template +void make_heap_aux(RandomIter first, RandomIter last, Distance*) { + if (last - first < 2) { + return; + } + auto len = last - first; + auto holeIndex = (len - 2) / 2; + while (true) { + // 重排以 holeIndex 为首的子树 + mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex)); + if (holeIndex == 0) { return; - auto len = last - first; - auto holeIndex = (len - 2) / 2; - while (true) { - // 重排以 holeIndex 为首的子树 - mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex)); - if (holeIndex == 0) - return; - holeIndex--; } - } - - template - void make_heap(RandomIter first, RandomIter last) { - mystl::make_heap_aux(first, last, distance_type(first)); - ; - } - - // 重载版本使用函数对象 comp 代替比较操作 - template - void make_heap_aux(RandomIter first, RandomIter last, Distance *, - Compared comp) { - if (last - first < 2) + holeIndex--; + } +} + +template +void make_heap(RandomIter first, RandomIter last) { + mystl::make_heap_aux(first, last, distance_type(first)); + ; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void make_heap_aux(RandomIter first, RandomIter last, Distance*, + Compared comp) { + if (last - first < 2) { + return; + } + auto len = last - first; + auto holeIndex = (len - 2) / 2; + while (true) { + // 重排以 holeIndex 为首的子树 + mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex), comp); + if (holeIndex == 0) { return; - auto len = last - first; - auto holeIndex = (len - 2) / 2; - while (true) { - // 重排以 holeIndex 为首的子树 - mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex), - comp); - if (holeIndex == 0) - return; - holeIndex--; } + holeIndex--; } +} - template - void make_heap(RandomIter first, RandomIter last, Compared comp) { - mystl::make_heap_aux(first, last, distance_type(first), comp); - } -}; +template +void make_heap(RandomIter first, RandomIter last, Compared comp) { + mystl::make_heap_aux(first, last, distance_type(first), comp); +} +}; // namespace mystl -#endif /* _HEAP_ALGO_ */ +#endif /* SIMPLEKERNEL_HEAP_ALGO */ diff --git a/src/libcxx/include/initializer_list b/src/libcxx/include/initializer_list index 127971cd4..f6306ca51 100644 --- a/src/libcxx/include/initializer_list +++ b/src/libcxx/include/initializer_list @@ -1,78 +1,91 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/gcc-mirror/gcc -// initializer_list for Simple-XX/SimpleKernel. +/** + * @file initializer_list + * @brief stl initializer_list 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ /** @file initializer_list * This is a Standard C++ Library header. */ -#ifndef _INITIALIZER_LIST_ -#define _INITIALIZER_LIST_ - -namespace std { - /// initializer_list - template - class initializer_list { - public: - typedef _E value_type; - typedef const _E &reference; - typedef const _E &const_reference; - typedef size_t size_type; - typedef const _E *iterator; - typedef const _E *const_iterator; +#ifndef SIMPLEKERNEL_INITIALIZER_LIST +#define SIMPLEKERNEL_INITIALIZER_LIST - private: - iterator _M_array; - size_type _M_len; +#include "cstddef" - // The compiler can call a private constructor. - constexpr initializer_list(const_iterator __a, size_type __l) - : _M_array(__a), _M_len(__l) { - } +namespace std { +/// initializer_list +template +class initializer_list { +public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + typedef const _E* iterator; + typedef const _E* const_iterator; - public: - constexpr initializer_list() noexcept : _M_array(0), _M_len(0) { - } +private: + iterator _M_array; + size_type _M_len; - // Number of elements. - constexpr size_type size() const noexcept { - return _M_len; - } + // The compiler can call a private constructor. + constexpr initializer_list(const_iterator __a, size_type __l) + : _M_array(__a), _M_len(__l) { + } - // First element. - constexpr const_iterator begin() const noexcept { - return _M_array; - } +public: + constexpr initializer_list() noexcept : _M_array(0), _M_len(0) { + } - // One past the last element. - constexpr const_iterator end() const noexcept { - return begin() + size(); - } - }; + // Number of elements. + constexpr size_type size() const noexcept { + return _M_len; + } - /** - * @brief Return an iterator pointing to the first element of - * the initializer_list. - * @param __ils Initializer list. - * @relates initializer_list - */ - template - constexpr const _Tp *begin(initializer_list<_Tp> __ils) noexcept { - return __ils.begin(); + // First element. + constexpr const_iterator begin() const noexcept { + return _M_array; } - /** - * @brief Return an iterator pointing to one past the last element - * of the initializer_list. - * @param __ils Initializer list. - * @relates initializer_list - */ - template - constexpr const _Tp *end(initializer_list<_Tp> __ils) noexcept { - return __ils.end(); + // One past the last element. + constexpr const_iterator end() const noexcept { + return begin() + size(); } }; -#endif /* _INITIALIZER_LIST_ */ +/** + * @brief Return an iterator pointing to the first element of + * the initializer_list. + * @param __ils Initializer list. + * @relates initializer_list + */ +template +constexpr const _Tp* begin(initializer_list<_Tp> __ils) noexcept { + return __ils.begin(); +} + +/** + * @brief Return an iterator pointing to one past the last element + * of the initializer_list. + * @param __ils Initializer list. + * @relates initializer_list + */ +template +constexpr const _Tp* end(initializer_list<_Tp> __ils) noexcept { + return __ils.end(); +} +}; // namespace std + +#endif /* SIMPLEKERNEL_INITIALIZER_LIST */ diff --git a/src/libcxx/include/iostream b/src/libcxx/include/iostream index 5858274fc..9a8172947 100755 --- a/src/libcxx/include/iostream +++ b/src/libcxx/include/iostream @@ -1,35 +1,53 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/MRNIU/MiniCRT -// iostream for Simple-XX/SimpleKernel. +/** + * @file iostream + * @brief C++ 输入输出 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/MRNIU/MiniCRT + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ -#ifndef _IOSTREAM_ -#define _IOSTREAM_ +#ifndef SIMPLEKERNEL_IOSTREAM +#define SIMPLEKERNEL_IOSTREAM + +#include "cstdint" namespace std { - class ostream { - private: - protected: - ostream(const ostream &lhs); - - public: - ostream(void); - ~ostream(void); - ostream &operator<<(char c); - ostream &operator<<(int n); - ostream &operator<<(unsigned int n); - ostream &operator<<(long n); - ostream &operator<<(unsigned long n); - ostream &operator<<(const char *lhs); - ostream &operator<<(ostream &(*)(ostream &)); - }; +class ostream { +private: + +protected: + ostream(const ostream& lhs); - inline ostream &endl(ostream &lhs) { - return lhs << '\n'; - } +public: + enum openmode : uint8_t { + in = 1, + out = 2, + binary = 4, + trunc = 8, + }; - static ostream cout; + ostream(void); + ~ostream(void); + ostream& operator<<(char c); + ostream& operator<<(int n); + ostream& operator<<(const char* lhs); + ostream& operator<<(ostream& (*)(ostream&)); }; -#endif /* _IOSTREAM_ */ +inline ostream& endl(ostream& lhs) { + return lhs << '\n'; +} + +static ostream cout; +}; // namespace std + +#endif /* SIMPLEKERNEL_IOSTREAM */ diff --git a/src/libcxx/include/iterator b/src/libcxx/include/iterator index 6e43720c2..e26df2118 100644 --- a/src/libcxx/include/iterator +++ b/src/libcxx/include/iterator @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// iterator for Simple-XX/SimpleKernel. - -#ifndef _ITERATOR_ -#define _ITERATOR_ +/** + * @file iterator + * @brief stl iterator 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_ITERATOR +#define SIMPLEKERNEL_ITERATOR // 这个头文件用于迭代器设计,包含了一些模板结构体与全局函数, @@ -14,342 +25,353 @@ namespace mystl { - // 五种迭代器类型 - struct input_iterator_tag {}; - struct output_iterator_tag {}; - struct forward_iterator_tag : public input_iterator_tag {}; - struct bidirectional_iterator_tag : public forward_iterator_tag {}; - struct random_access_iterator_tag : public bidirectional_iterator_tag {}; - - // iterator 模板 - template - struct iterator { - typedef Category iterator_category; - typedef T value_type; - typedef Pointer pointer; - typedef Reference reference; - typedef Distance difference_type; - }; +// 五种迭代器类型 +struct input_iterator_tag { }; - // iterator traits - - template - struct has_iterator_cat { - private: - struct two { - char a; - char b; - }; - template - static two test(...); - template - static char test(typename U::iterator_category * = 0); - - public: - static const bool value = sizeof(test(0)) == sizeof(char); - }; +struct output_iterator_tag { }; - template - struct iterator_traits_impl {}; +struct forward_iterator_tag : public input_iterator_tag { }; - template - struct iterator_traits_impl { - typedef typename Iterator::iterator_category iterator_category; - typedef typename Iterator::value_type value_type; - typedef typename Iterator::pointer pointer; - typedef typename Iterator::reference reference; - typedef typename Iterator::difference_type difference_type; - }; +struct bidirectional_iterator_tag : public forward_iterator_tag { }; - template - struct iterator_traits_helper {}; - - template - struct iterator_traits_helper - : public iterator_traits_impl< - Iterator, - std::is_convertible::value || - std::is_convertible::value> {}; - - // 萃取迭代器的特性 - template - struct iterator_traits - : public iterator_traits_helper::value> {}; - - // 针对原生指针的偏特化版本 - template - struct iterator_traits { - typedef random_access_iterator_tag iterator_category; - typedef T value_type; - typedef T * pointer; - typedef T & reference; - typedef ptrdiff_t difference_type; - }; +struct random_access_iterator_tag : public bidirectional_iterator_tag { }; - template - struct iterator_traits { - typedef random_access_iterator_tag iterator_category; - typedef T value_type; - typedef const T * pointer; - typedef const T & reference; - typedef ptrdiff_t difference_type; - }; +// iterator 模板 +template +struct iterator { + typedef Category iterator_category; + typedef T value_type; + typedef Pointer pointer; + typedef Reference reference; + typedef Distance difference_type; +}; - template >::value> - struct has_iterator_cat_of - : public m_bool_constant::iterator_category, U>::value> {}; - - // 萃取某种迭代器 - template - struct has_iterator_cat_of : public m_false_type {}; - - template - struct is_input_iterator - : public has_iterator_cat_of {}; - - template - struct is_output_iterator - : public has_iterator_cat_of {}; - - template - struct is_forward_iterator - : public has_iterator_cat_of {}; - - template - struct is_bidirectional_iterator - : public has_iterator_cat_of {}; - - template - struct is_random_access_iterator - : public has_iterator_cat_of {}; - - template - struct is_iterator - : public m_bool_constant::value || - is_output_iterator::value> {}; - - // 萃取某个迭代器的 category - template - typename iterator_traits::iterator_category - iterator_category(const Iterator &) { - typedef typename iterator_traits::iterator_category Category; - return Category(); - } +// iterator traits - // 萃取某个迭代器的 distance_type - template - typename iterator_traits::difference_type * - distance_type(const Iterator &) { - return static_cast< - typename iterator_traits::difference_type *>(0); - } +template +struct has_iterator_cat { +private: + struct two { + char a; + char b; + }; + template + static two test(...); + template + static char test(typename U::iterator_category* = 0); - // 萃取某个迭代器的 value_type - template - typename iterator_traits::value_type * - value_type(const Iterator &) { - return static_cast::value_type *>(0); - } +public: + static const bool value = sizeof(test(0)) == sizeof(char); +}; - // 以下函数用于计算迭代器间的距离 - - // distance 的 input_iterator_tag 的版本 - template - typename iterator_traits::difference_type - distance_dispatch(InputIterator first, InputIterator last, - input_iterator_tag) { - typename iterator_traits::difference_type n = 0; - while (first != last) { - ++first; - ++n; - } - return n; - } +template +struct iterator_traits_impl { }; - // distance 的 random_access_iterator_tag 的版本 - template - typename iterator_traits::difference_type - distance_dispatch(RandomIter first, RandomIter last, - random_access_iterator_tag) { - return last - first; - } +template +struct iterator_traits_impl { + typedef typename Iterator::iterator_category iterator_category; + typedef typename Iterator::value_type value_type; + typedef typename Iterator::pointer pointer; + typedef typename Iterator::reference reference; + typedef typename Iterator::difference_type difference_type; +}; - template - typename iterator_traits::difference_type - distance(InputIterator first, InputIterator last) { - return distance_dispatch(first, last, iterator_category(first)); - } +template +struct iterator_traits_helper { }; + +template +struct iterator_traits_helper + : public iterator_traits_impl< + Iterator, std::is_convertible::value + || std::is_convertible::value> { }; + +// 萃取迭代器的特性 +template +struct iterator_traits + : public iterator_traits_helper::value> { }; + +// 针对原生指针的偏特化版本 +template +struct iterator_traits { + typedef random_access_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef ptrdiff_t difference_type; +}; - // 以下函数用于让迭代器前进 n 个距离 +template +struct iterator_traits { + typedef random_access_iterator_tag iterator_category; + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef ptrdiff_t difference_type; +}; - // advance 的 input_iterator_tag 的版本 - template - void advance_dispatch(InputIterator &i, Distance n, input_iterator_tag) { - while (n--) +template >::value> +struct has_iterator_cat_of + : public m_bool_constant::iterator_category, U>::value> { }; + +// 萃取某种迭代器 +template +struct has_iterator_cat_of : public m_false_type { }; + +template +struct is_input_iterator + : public has_iterator_cat_of { }; + +template +struct is_output_iterator + : public has_iterator_cat_of { }; + +template +struct is_forward_iterator + : public has_iterator_cat_of { }; + +template +struct is_bidirectional_iterator + : public has_iterator_cat_of { }; + +template +struct is_random_access_iterator + : public has_iterator_cat_of { }; + +template +struct is_iterator + : public m_bool_constant::value + || is_output_iterator::value> { }; + +// 萃取某个迭代器的 category +template +typename iterator_traits::iterator_category +iterator_category(const Iterator&) { + typedef typename iterator_traits::iterator_category Category; + return Category(); +} + +// 萃取某个迭代器的 distance_type +template +typename iterator_traits::difference_type* +distance_type(const Iterator&) { + return static_cast::difference_type*>(0); +} + +// 萃取某个迭代器的 value_type +template +typename iterator_traits::value_type* value_type(const Iterator&) { + return static_cast::value_type*>(0); +} + +// 以下函数用于计算迭代器间的距离 + +// distance 的 input_iterator_tag 的版本 +template +typename iterator_traits::difference_type +distance_dispatch(InputIterator first, InputIterator last, input_iterator_tag) { + typename iterator_traits::difference_type n = 0; + while (first != last) { + ++first; + ++n; + } + return n; +} + +// distance 的 random_access_iterator_tag 的版本 +template +typename iterator_traits::difference_type +distance_dispatch(RandomIter first, RandomIter last, + random_access_iterator_tag) { + return last - first; +} + +template +typename iterator_traits::difference_type +distance(InputIterator first, InputIterator last) { + return distance_dispatch(first, last, iterator_category(first)); +} + +// 以下函数用于让迭代器前进 n 个距离 + +// advance 的 input_iterator_tag 的版本 +template +void advance_dispatch(InputIterator& i, Distance n, input_iterator_tag) { + while (n--) { + ++i; + } +} + +// advance 的 bidirectional_iterator_tag 的版本 +template +void advance_dispatch(BidirectionalIterator& i, Distance n, + bidirectional_iterator_tag) { + if (n >= 0) { + while (n--) { ++i; + } } - - // advance 的 bidirectional_iterator_tag 的版本 - template - void advance_dispatch(BidirectionalIterator &i, Distance n, - bidirectional_iterator_tag) { - if (n >= 0) - while (n--) - ++i; - else - while (n++) - --i; + else { + while (n++) { + --i; + } } - - // advance 的 random_access_iterator_tag 的版本 - template - void advance_dispatch(RandomIter &i, Distance n, - random_access_iterator_tag) { - i += n; +} + +// advance 的 random_access_iterator_tag 的版本 +template +void advance_dispatch(RandomIter& i, Distance n, random_access_iterator_tag) { + i += n; +} + +template +void advance(InputIterator& i, Distance n) { + advance_dispatch(i, n, iterator_category(i)); +} + +/*****************************************************************************************/ + +// 模板类 : reverse_iterator +// 代表反向迭代器,使前进为后退,后退为前进 +template +class reverse_iterator { +private: + Iterator current; // 记录对应的正向迭代器 + +public: + // 反向迭代器的五种相应型别 + typedef + typename iterator_traits::iterator_category iterator_category; + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::pointer pointer; + typedef typename iterator_traits::reference reference; + + typedef Iterator iterator_type; + typedef reverse_iterator self; + +public: + // 构造函数 + reverse_iterator() { } - template - void advance(InputIterator &i, Distance n) { - advance_dispatch(i, n, iterator_category(i)); + explicit reverse_iterator(iterator_type i) : current(i) { } - /*****************************************************************************************/ - - // 模板类 : reverse_iterator - // 代表反向迭代器,使前进为后退,后退为前进 - template - class reverse_iterator { - private: - Iterator current; // 记录对应的正向迭代器 - - public: - // 反向迭代器的五种相应型别 - typedef typename iterator_traits::iterator_category - iterator_category; - typedef typename iterator_traits::value_type value_type; - typedef - typename iterator_traits::difference_type difference_type; - typedef typename iterator_traits::pointer pointer; - typedef typename iterator_traits::reference reference; - - typedef Iterator iterator_type; - typedef reverse_iterator self; - - public: - // 构造函数 - reverse_iterator() { - } - explicit reverse_iterator(iterator_type i) : current(i) { - } - reverse_iterator(const self &rhs) : current(rhs.current) { - } + reverse_iterator(const self& rhs) : current(rhs.current) { + } - public: - // 取出对应的正向迭代器 - iterator_type base() const { - return current; - } +public: + // 取出对应的正向迭代器 + iterator_type base() const { + return current; + } - // 重载操作符 - reference operator*() const { // 实际对应正向迭代器的前一个位置 - auto tmp = current; - return *--tmp; - } - pointer operator->() const { - return &(operator*()); - } + // 重载操作符 + reference operator*() const { // 实际对应正向迭代器的前一个位置 + auto tmp = current; + return *--tmp; + } - // 前进(++)变为后退(--) - self &operator++() { - --current; - return *this; - } - self operator++(int) { - self tmp = *this; - --current; - return tmp; - } - // 后退(--)变为前进(++) - self &operator--() { - ++current; - return *this; - } - self operator--(int) { - self tmp = *this; - ++current; - return tmp; - } + pointer operator->() const { + return &(operator*()); + } - self &operator+=(difference_type n) { - current -= n; - return *this; - } - self operator+(difference_type n) const { - return self(current - n); - } - self &operator-=(difference_type n) { - current += n; - return *this; - } - self operator-(difference_type n) const { - return self(current + n); - } + // 前进(++)变为后退(--) + self& operator++() { + --current; + return *this; + } - reference operator[](difference_type n) const { - return *(*this + n); - } - }; + self operator++(int) { + self tmp = *this; + --current; + return tmp; + } - // 重载 operator- - template - typename reverse_iterator::difference_type - operator-(const reverse_iterator &lhs, - const reverse_iterator &rhs) { - return rhs.base() - lhs.base(); + // 后退(--)变为前进(++) + self& operator--() { + ++current; + return *this; } - // 重载比较操作符 - template - bool operator==(const reverse_iterator &lhs, - const reverse_iterator &rhs) { - return lhs.base() == rhs.base(); + self operator--(int) { + self tmp = *this; + ++current; + return tmp; } - template - bool operator<(const reverse_iterator &lhs, - const reverse_iterator &rhs) { - return rhs.base() < lhs.base(); + self& operator+=(difference_type n) { + current -= n; + return *this; } - template - bool operator!=(const reverse_iterator &lhs, - const reverse_iterator &rhs) { - return !(lhs == rhs); + self operator+(difference_type n) const { + return self(current - n); } - template - bool operator>(const reverse_iterator &lhs, - const reverse_iterator &rhs) { - return rhs < lhs; + self& operator-=(difference_type n) { + current += n; + return *this; } - template - bool operator<=(const reverse_iterator &lhs, - const reverse_iterator &rhs) { - return !(rhs < lhs); + self operator-(difference_type n) const { + return self(current + n); } - template - bool operator>=(const reverse_iterator &lhs, - const reverse_iterator &rhs) { - return !(lhs < rhs); + reference operator[](difference_type n) const { + return *(*this + n); } }; -#endif /* _ITERATOR_ */ +// 重载 operator- +template +typename reverse_iterator::difference_type +operator-(const reverse_iterator& lhs, + const reverse_iterator& rhs) { + return rhs.base() - lhs.base(); +} + +// 重载比较操作符 +template +bool operator==(const reverse_iterator& lhs, + const reverse_iterator& rhs) { + return lhs.base() == rhs.base(); +} + +template +bool operator<(const reverse_iterator& lhs, + const reverse_iterator& rhs) { + return rhs.base() < lhs.base(); +} + +template +bool operator!=(const reverse_iterator& lhs, + const reverse_iterator& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const reverse_iterator& lhs, + const reverse_iterator& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const reverse_iterator& lhs, + const reverse_iterator& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const reverse_iterator& lhs, + const reverse_iterator& rhs) { + return !(lhs < rhs); +} +}; // namespace mystl + +#endif /* SIMPLEKERNEL_ITERATOR */ diff --git a/src/libcxx/include/list b/src/libcxx/include/list index f522a5968..a19e085c6 100644 --- a/src/libcxx/include/list +++ b/src/libcxx/include/list @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// list for Simple-XX/SimpleKernel. - -#ifndef _LIST_ -#define _LIST_ +/** + * @file list + * @brief stl list 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_LIST +#define SIMPLEKERNEL_LIST // 这个头文件包含了一个模板类 list // list : 双向链表 @@ -22,1041 +33,1082 @@ // * push_back // * insert +#include "exceptdef" +#include "functional" #include "initializer_list" #include "iterator" #include "memory" -#include "functional" #include "util" -#include "exceptdef" namespace mystl { - template - struct list_node_base; - template - struct list_node; +template +struct list_node_base; +template +struct list_node; - template - struct node_traits { - typedef list_node_base *base_ptr; - typedef list_node * node_ptr; - }; +template +struct node_traits { + typedef list_node_base* base_ptr; + typedef list_node* node_ptr; +}; - // list 的节点结构 +// list 的节点结构 - template - struct list_node_base { - typedef typename node_traits::base_ptr base_ptr; - typedef typename node_traits::node_ptr node_ptr; +template +struct list_node_base { + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; - base_ptr prev; // 前一节点 - base_ptr next; // 下一节点 + base_ptr prev; // 前一节点 + base_ptr next; // 下一节点 - list_node_base() = default; + list_node_base() = default; - node_ptr as_node() { - return static_cast(self()); - } + node_ptr as_node() { + return static_cast(self()); + } - void unlink() { - prev = next = self(); - } + void unlink() { + prev = next = self(); + } - base_ptr self() { - return static_cast(&*this); - } - }; + base_ptr self() { + return static_cast(&*this); + } +}; - template - struct list_node : public list_node_base { - typedef typename node_traits::base_ptr base_ptr; - typedef typename node_traits::node_ptr node_ptr; +template +struct list_node : public list_node_base { + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; - T value; // 数据域 + T value; // 数据域 - list_node() = default; - list_node(const T &v) : value(v) { - } - list_node(T &&v) : value(mystl::move(v)) { - } + list_node() = default; - base_ptr as_base() { - return static_cast(&*this); - } - node_ptr self() { - return static_cast(&*this); - } - }; - - // list 的迭代器设计 - template - struct list_iterator - : public mystl::iterator { - typedef T value_type; - typedef T * pointer; - typedef T & reference; - typedef typename node_traits::base_ptr base_ptr; - typedef typename node_traits::node_ptr node_ptr; - typedef list_iterator self; - - base_ptr node_; // 指向当前节点 - - // 构造函数 - list_iterator() = default; - list_iterator(base_ptr x) : node_(x) { - } - list_iterator(node_ptr x) : node_(x->as_base()) { - } - list_iterator(const list_iterator &rhs) : node_(rhs.node_) { - } + list_node(const T& v) : value(v) { + } - // 重载操作符 - reference operator*() const { - return node_->as_node()->value; - } - pointer operator->() const { - return &(operator*()); - } + list_node(T&& v) : value(mystl::move(v)) { + } - self &operator++() { - MYSTL_DEBUG(node_ != nullptr); - node_ = node_->next; - return *this; - } - self operator++(int) { - self tmp = *this; - ++*this; - return tmp; - } - self &operator--() { - MYSTL_DEBUG(node_ != nullptr); - node_ = node_->prev; - return *this; - } - self operator--(int) { - self tmp = *this; - --*this; - return tmp; - } + base_ptr as_base() { + return static_cast(&*this); + } - // 重载比较操作符 - bool operator==(const self &rhs) const { - return node_ == rhs.node_; - } - bool operator!=(const self &rhs) const { - return node_ != rhs.node_; - } - }; - - template - struct list_const_iterator - : public iterator { - typedef T value_type; - typedef const T * pointer; - typedef const T & reference; - typedef typename node_traits::base_ptr base_ptr; - typedef typename node_traits::node_ptr node_ptr; - typedef list_const_iterator self; - - base_ptr node_; - - list_const_iterator() = default; - list_const_iterator(base_ptr x) : node_(x) { - } - list_const_iterator(node_ptr x) : node_(x->as_base()) { - } - list_const_iterator(const list_iterator &rhs) : node_(rhs.node_) { - } - list_const_iterator(const list_const_iterator &rhs) : node_(rhs.node_) { - } + node_ptr self() { + return static_cast(&*this); + } +}; - reference operator*() const { - return node_->as_node()->value; - } - pointer operator->() const { - return &(operator*()); - } +// list 的迭代器设计 +template +struct list_iterator + : public mystl::iterator { + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + typedef list_iterator self; - self &operator++() { - MYSTL_DEBUG(node_ != nullptr); - node_ = node_->next; - return *this; - } - self operator++(int) { - self tmp = *this; - ++*this; - return tmp; - } - self &operator--() { - MYSTL_DEBUG(node_ != nullptr); - node_ = node_->prev; - return *this; - } - self operator--(int) { - self tmp = *this; - --*this; - return tmp; - } + base_ptr node_; // 指向当前节点 - // 重载比较操作符 - bool operator==(const self &rhs) const { - return node_ == rhs.node_; - } - bool operator!=(const self &rhs) const { - return node_ != rhs.node_; - } - }; - - // 模板类: list - // 模板参数 T 代表数据类型 - template - class list { - public: - // list 的嵌套型别定义 - typedef mystl::allocator allocator_type; - typedef mystl::allocator data_allocator; - typedef mystl::allocator> base_allocator; - typedef mystl::allocator> node_allocator; - - typedef typename allocator_type::value_type value_type; - typedef typename allocator_type::pointer pointer; - typedef typename allocator_type::const_pointer const_pointer; - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - typedef typename allocator_type::size_type size_type; - typedef typename allocator_type::difference_type difference_type; - - typedef list_iterator iterator; - typedef list_const_iterator const_iterator; - typedef mystl::reverse_iterator reverse_iterator; - typedef mystl::reverse_iterator const_reverse_iterator; - - typedef typename node_traits::base_ptr base_ptr; - typedef typename node_traits::node_ptr node_ptr; - - allocator_type get_allocator() { - return node_allocator(); - } + // 构造函数 + list_iterator() = default; - private: - base_ptr node_; // 指向末尾节点 - size_type size_; // 大小 + list_iterator(base_ptr x) : node_(x) { + } - public: - // 构造、复制、移动、析构函数 - list() { - fill_init(0, value_type()); - } + list_iterator(node_ptr x) : node_(x->as_base()) { + } - explicit list(size_type n) { - fill_init(n, value_type()); - } + list_iterator(const list_iterator& rhs) : node_(rhs.node_) { + } - list(size_type n, const T &value) { - fill_init(n, value); - } + // 重载操作符 + reference operator*() const { + return node_->as_node()->value; + } - template ::value, - int>::type = 0> - list(Iter first, Iter last) { - copy_init(first, last); - } + pointer operator->() const { + return &(operator*()); + } - list(std::initializer_list ilist) { - copy_init(ilist.begin(), ilist.end()); - } + self& operator++() { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->next; + return *this; + } - list(const list &rhs) { - copy_init(rhs.cbegin(), rhs.cend()); - } + self operator++(int) { + self tmp = *this; + ++*this; + return tmp; + } - list(list &&rhs) noexcept : node_(rhs.node_), size_(rhs.size_) { - rhs.node_ = nullptr; - rhs.size_ = 0; - } + self& operator--() { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->prev; + return *this; + } - list &operator=(const list &rhs) { - if (this != &rhs) { - assign(rhs.begin(), rhs.end()); - } - return *this; - } + self operator--(int) { + self tmp = *this; + --*this; + return tmp; + } - list &operator=(list &&rhs) noexcept { - clear(); - splice(end(), rhs); - return *this; - } + // 重载比较操作符 + bool operator==(const self& rhs) const { + return node_ == rhs.node_; + } - list &operator=(std::initializer_list ilist) { - list tmp(ilist.begin(), ilist.end()); - swap(tmp); - return *this; - } + bool operator!=(const self& rhs) const { + return node_ != rhs.node_; + } +}; - ~list() { - if (node_) { - clear(); - base_allocator::deallocate(node_); - node_ = nullptr; - size_ = 0; - } - } +template +struct list_const_iterator : public iterator { + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + typedef list_const_iterator self; - public: - // 迭代器相关操作 - iterator begin() noexcept { - return node_->next; - } - const_iterator begin() const noexcept { - return node_->next; - } - iterator end() noexcept { - return node_; - } - const_iterator end() const noexcept { - return node_; - } + base_ptr node_; - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return reverse_iterator(begin()); - } + list_const_iterator() = default; - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } + list_const_iterator(base_ptr x) : node_(x) { + } - // 容量相关操作 - bool empty() const noexcept { - return node_->next == node_; - } + list_const_iterator(node_ptr x) : node_(x->as_base()) { + } - size_type size() const noexcept { - return size_; - } + list_const_iterator(const list_iterator& rhs) : node_(rhs.node_) { + } - size_type max_size() const noexcept { - return static_cast(-1); - } + list_const_iterator(const list_const_iterator& rhs) : node_(rhs.node_) { + } - // 访问元素相关操作 - reference front() { - MYSTL_DEBUG(!empty()); - return *begin(); - } + reference operator*() const { + return node_->as_node()->value; + } - const_reference front() const { - MYSTL_DEBUG(!empty()); - return *begin(); - } + pointer operator->() const { + return &(operator*()); + } - reference back() { - MYSTL_DEBUG(!empty()); - return *(--end()); - } + self& operator++() { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->next; + return *this; + } - const_reference back() const { - MYSTL_DEBUG(!empty()); - return *(--end()); - } + self operator++(int) { + self tmp = *this; + ++*this; + return tmp; + } - // 调整容器相关操作 + self& operator--() { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->prev; + return *this; + } - // assign + self operator--(int) { + self tmp = *this; + --*this; + return tmp; + } - void assign(size_type n, const value_type &value) { - fill_assign(n, value); - } + // 重载比较操作符 + bool operator==(const self& rhs) const { + return node_ == rhs.node_; + } - template ::value, - int>::type = 0> - void assign(Iter first, Iter last) { - copy_assign(first, last); - } + bool operator!=(const self& rhs) const { + return node_ != rhs.node_; + } +}; - void assign(std::initializer_list ilist) { - copy_assign(ilist.begin(), ilist.end()); - } +// 模板类: list +// 模板参数 T 代表数据类型 +template +class list { +public: + // list 的嵌套型别定义 + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator> base_allocator; + typedef mystl::allocator> node_allocator; + + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef list_iterator iterator; + typedef list_const_iterator const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + + allocator_type get_allocator() { + return node_allocator(); + } - // emplace_front / emplace_back / emplace +private: + base_ptr node_; // 指向末尾节点 + size_type size_; // 大小 - template - void emplace_front(Args &&...args) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); - auto link_node = create_node(mystl::forward(args)...); - link_nodes_at_front(link_node->as_base(), link_node->as_base()); - ++size_; - } +public: + // 构造、复制、移动、析构函数 + list() { + fill_init(0, value_type()); + } - template - void emplace_back(Args &&...args) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); - auto link_node = create_node(mystl::forward(args)...); - link_nodes_at_back(link_node->as_base(), link_node->as_base()); - ++size_; - } + explicit list(size_type n) { + fill_init(n, value_type()); + } - template - iterator emplace(const_iterator pos, Args &&...args) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); - auto link_node = create_node(mystl::forward(args)...); - link_nodes(pos.node_, link_node->as_base(), link_node->as_base()); - ++size_; - return iterator(link_node); - } + list(size_type n, const T& value) { + fill_init(n, value); + } - // insert + template ::value, int>::type + = 0> + list(Iter first, Iter last) { + copy_init(first, last); + } - iterator insert(const_iterator pos, const value_type &value) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); - auto link_node = create_node(value); - ++size_; - return link_iter_node(pos, link_node->as_base()); - } + list(std::initializer_list ilist) { + copy_init(ilist.begin(), ilist.end()); + } - iterator insert(const_iterator pos, value_type &&value) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); - auto link_node = create_node(mystl::move(value)); - ++size_; - return link_iter_node(pos, link_node->as_base()); - } + list(const list& rhs) { + copy_init(rhs.cbegin(), rhs.cend()); + } - iterator insert(const_iterator pos, size_type n, - const value_type &value) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - n, - "list's size too big"); - return fill_insert(pos, n, value); - } + list(list&& rhs) noexcept : node_(rhs.node_), size_(rhs.size_) { + rhs.node_ = nullptr; + rhs.size_ = 0; + } - template ::value, - int>::type = 0> - iterator insert(const_iterator pos, Iter first, Iter last) { - size_type n = mystl::distance(first, last); - THROW_LENGTH_ERROR_IF(size_ > max_size() - n, - "list's size too big"); - return copy_insert(pos, n, first); + list& operator=(const list& rhs) { + if (this != &rhs) { + assign(rhs.begin(), rhs.end()); } + return *this; + } - // push_front / push_back + list& operator=(list&& rhs) noexcept { + clear(); + splice(end(), rhs); + return *this; + } - void push_front(const value_type &value) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); - auto link_node = create_node(value); - link_nodes_at_front(link_node->as_base(), link_node->as_base()); - ++size_; - } + list& operator=(std::initializer_list ilist) { + list tmp(ilist.begin(), ilist.end()); + swap(tmp); + return *this; + } - void push_front(value_type &&value) { - emplace_front(mystl::move(value)); + ~list() { + if (node_) { + clear(); + base_allocator::deallocate(node_); + node_ = nullptr; + size_ = 0; } + } - void push_back(const value_type &value) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); - auto link_node = create_node(value); - link_nodes_at_back(link_node->as_base(), link_node->as_base()); - ++size_; - } +public: + // 迭代器相关操作 + iterator begin() noexcept { + return node_->next; + } - void push_back(value_type &&value) { - emplace_back(mystl::move(value)); - } + const_iterator begin() const noexcept { + return node_->next; + } - // pop_front / pop_back + iterator end() noexcept { + return node_; + } - void pop_front() { - MYSTL_DEBUG(!empty()); - auto n = node_->next; - unlink_nodes(n, n); - destroy_node(n->as_node()); - --size_; - } + const_iterator end() const noexcept { + return node_; + } - void pop_back() { - MYSTL_DEBUG(!empty()); - auto n = node_->prev; - unlink_nodes(n, n); - destroy_node(n->as_node()); - --size_; - } + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } - // erase / clear + const_reverse_iterator rbegin() const noexcept { + return reverse_iterator(end()); + } - iterator erase(const_iterator pos); - iterator erase(const_iterator first, const_iterator last); + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - void clear(); + const_reverse_iterator rend() const noexcept { + return reverse_iterator(begin()); + } - // resize + const_iterator cbegin() const noexcept { + return begin(); + } - void resize(size_type new_size) { - resize(new_size, value_type()); - } - void resize(size_type new_size, const value_type &value); + const_iterator cend() const noexcept { + return end(); + } - void swap(list &rhs) noexcept { - mystl::swap(node_, rhs.node_); - mystl::swap(size_, rhs.size_); - } + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } - // list 相关操作 + const_reverse_iterator crend() const noexcept { + return rend(); + } - void splice(const_iterator pos, list &other); - void splice(const_iterator pos, list &other, const_iterator it); - void splice(const_iterator pos, list &other, const_iterator first, - const_iterator last); + // 容量相关操作 + bool empty() const noexcept { + return node_->next == node_; + } - void remove(const value_type &value) { - remove_if([&](const value_type &v) { - return v == value; - }); - } - template - void remove_if(UnaryPredicate pred); + size_type size() const noexcept { + return size_; + } - void unique() { - unique(mystl::equal_to()); - } - template - void unique(BinaryPredicate pred); + size_type max_size() const noexcept { + return static_cast(-1); + } - void merge(list &x) { - merge(x, mystl::less()); - } - template - void merge(list &x, Compare comp); + // 访问元素相关操作 + reference front() { + MYSTL_DEBUG(!empty()); + return *begin(); + } - void sort() { - list_sort(begin(), end(), size(), mystl::less()); - } - template - void sort(Compared comp) { - list_sort(begin(), end(), size(), comp); - } + const_reference front() const { + MYSTL_DEBUG(!empty()); + return *begin(); + } - void reverse(); - - private: - // helper functions - - // create / destroy node - template - node_ptr create_node(Args &&...agrs); - void destroy_node(node_ptr p); - - // initialize - void fill_init(size_type n, const value_type &value); - template - void copy_init(Iter first, Iter last); - - // link / unlink - iterator link_iter_node(const_iterator pos, base_ptr node); - void link_nodes(base_ptr p, base_ptr first, base_ptr last); - void link_nodes_at_front(base_ptr first, base_ptr last); - void link_nodes_at_back(base_ptr first, base_ptr last); - void unlink_nodes(base_ptr f, base_ptr l); - - // assign - void fill_assign(size_type n, const value_type &value); - template - void copy_assign(Iter first, Iter last); - - // insert - iterator fill_insert(const_iterator pos, size_type n, - const value_type &value); - template - iterator copy_insert(const_iterator pos, size_type n, Iter first); - - // sort - template - iterator list_sort(iterator first, iterator last, size_type n, - Compared comp); - }; - - /*****************************************************************************************/ - - // 删除 pos 处的元素 - template - typename list::iterator list::erase(const_iterator pos) { - MYSTL_DEBUG(pos != cend()); - auto n = pos.node_; - auto next = n->next; - unlink_nodes(n, n); - destroy_node(n->as_node()); - --size_; - return iterator(next); - } - - // 删除 [first, last) 内的元素 - template - typename list::iterator list::erase(const_iterator first, - const_iterator last) { - if (first != last) { - unlink_nodes(first.node_, last.node_->prev); - while (first != last) { - auto cur = first.node_; - ++first; - destroy_node(cur->as_node()); - --size_; - } - } - return iterator(last.node_); + reference back() { + MYSTL_DEBUG(!empty()); + return *(--end()); } - // 清空 list - template - void list::clear() { - if (size_ != 0) { - auto cur = node_->next; - for (base_ptr next = cur->next; cur != node_; - cur = next, next = cur->next) { - destroy_node(cur->as_node()); - } - node_->unlink(); - size_ = 0; - } + const_reference back() const { + MYSTL_DEBUG(!empty()); + return *(--end()); } - // 重置容器大小 - template - void list::resize(size_type new_size, const value_type &value) { - auto i = begin(); - size_type len = 0; - while (i != end() && len < new_size) { - ++i; - ++len; - } - if (len == new_size) { - erase(i, node_); - } - else { - insert(node_, new_size - len, value); - } + // 调整容器相关操作 + + // assign + + void assign(size_type n, const value_type& value) { + fill_assign(n, value); } - // 将 list x 接合于 pos 之前 - template - void list::splice(const_iterator pos, list &x) { - MYSTL_DEBUG(this != &x); - if (!x.empty()) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, - "list's size too big"); + template ::value, int>::type + = 0> + void assign(Iter first, Iter last) { + copy_assign(first, last); + } - auto f = x.node_->next; - auto l = x.node_->prev; + void assign(std::initializer_list ilist) { + copy_assign(ilist.begin(), ilist.end()); + } - x.unlink_nodes(f, l); - link_nodes(pos.node_, f, l); + // emplace_front / emplace_back / emplace - size_ += x.size_; - x.size_ = 0; - } + template + void emplace_front(Args&&... args) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::forward(args)...); + link_nodes_at_front(link_node->as_base(), link_node->as_base()); + ++size_; } - // 将 it 所指的节点接合于 pos 之前 - template - void list::splice(const_iterator pos, list &x, const_iterator it) { - if (pos.node_ != it.node_ && pos.node_ != it.node_->next) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, - "list's size too big"); + template + void emplace_back(Args&&... args) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::forward(args)...); + link_nodes_at_back(link_node->as_base(), link_node->as_base()); + ++size_; + } - auto f = it.node_; + template + iterator emplace(const_iterator pos, Args&&... args) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::forward(args)...); + link_nodes(pos.node_, link_node->as_base(), link_node->as_base()); + ++size_; + return iterator(link_node); + } - x.unlink_nodes(f, f); - link_nodes(pos.node_, f, f); + // insert - ++size_; - --x.size_; - } + iterator insert(const_iterator pos, const value_type& value) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(value); + ++size_; + return link_iter_node(pos, link_node->as_base()); } - // 将 list x 的 [first, last) 内的节点接合于 pos 之前 - template - void list::splice(const_iterator pos, list &x, const_iterator first, - const_iterator last) { - if (first != last && this != &x) { - size_type n = mystl::distance(first, last); - THROW_LENGTH_ERROR_IF(size_ > max_size() - n, - "list's size too big"); - auto f = first.node_; - auto l = last.node_->prev; + iterator insert(const_iterator pos, value_type&& value) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::move(value)); + ++size_; + return link_iter_node(pos, link_node->as_base()); + } - x.unlink_nodes(f, l); - link_nodes(pos.node_, f, l); + iterator insert(const_iterator pos, size_type n, const value_type& value) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, "list's size too big"); + return fill_insert(pos, n, value); + } - size_ += n; - x.size_ -= n; - } + template ::value, int>::type + = 0> + iterator insert(const_iterator pos, Iter first, Iter last) { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, "list's size too big"); + return copy_insert(pos, n, first); } - // 将另一元操作 pred 为 true 的所有元素移除 - template - template - void list::remove_if(UnaryPredicate pred) { - auto f = begin(); - auto l = end(); - for (auto next = f; f != l; f = next) { - ++next; - if (pred(*f)) { - erase(f); - } - } + // push_front / push_back + + void push_front(const value_type& value) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(value); + link_nodes_at_front(link_node->as_base(), link_node->as_base()); + ++size_; } - // 移除 list 中满足 pred 为 true 重复元素 - template - template - void list::unique(BinaryPredicate pred) { - auto i = begin(); - auto e = end(); - auto j = i; - ++j; - while (j != e) { - if (pred(*i, *j)) { - erase(j); - } - else { - i = j; - } - j = i; - ++j; - } + void push_front(value_type&& value) { + emplace_front(mystl::move(value)); } - // 与另一个 list 合并,按照 comp 为 true 的顺序 - template - template - void list::merge(list &x, Compare comp) { - if (this != &x) { - THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, - "list's size too big"); - - auto f1 = begin(); - auto l1 = end(); - auto f2 = x.begin(); - auto l2 = x.end(); - - while (f1 != l1 && f2 != l2) { - if (comp(*f2, *f1)) { - // 使 comp 为 true 的一段区间 - auto next = f2; - ++next; - for (; next != l2 && comp(*next, *f1); ++next) - ; - auto f = f2.node_; - auto l = next.node_->prev; - f2 = next; - - // link node - x.unlink_nodes(f, l); - link_nodes(f1.node_, f, l); - ++f1; - } - else { - ++f1; - } - } - // 连接剩余部分 - if (f2 != l2) { - auto f = f2.node_; - auto l = l2.node_->prev; - x.unlink_nodes(f, l); - link_nodes(l1.node_, f, l); - } + void push_back(const value_type& value) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(value); + link_nodes_at_back(link_node->as_base(), link_node->as_base()); + ++size_; + } - size_ += x.size_; - x.size_ = 0; - } + void push_back(value_type&& value) { + emplace_back(mystl::move(value)); } - // 将 list 反转 - template - void list::reverse() { - if (size_ <= 1) { - return; - } - auto i = begin(); - auto e = end(); - while (i.node_ != e.node_) { - mystl::swap(i.node_->prev, i.node_->next); - i.node_ = i.node_->prev; - } - mystl::swap(e.node_->prev, e.node_->next); + // pop_front / pop_back + + void pop_front() { + MYSTL_DEBUG(!empty()); + auto n = node_->next; + unlink_nodes(n, n); + destroy_node(n->as_node()); + --size_; } - /*****************************************************************************************/ - // helper function + void pop_back() { + MYSTL_DEBUG(!empty()); + auto n = node_->prev; + unlink_nodes(n, n); + destroy_node(n->as_node()); + --size_; + } - // 创建结点 - template - template - typename list::node_ptr list::create_node(Args &&...args) { - node_ptr p = node_allocator::allocate(1); - try { - data_allocator::construct(mystl::address_of(p->value), - mystl::forward(args)...); - p->prev = nullptr; - p->next = nullptr; - } catch (...) { - node_allocator::deallocate(p); - throw; - } - return p; + // erase / clear + + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + + void clear(); + + // resize + + void resize(size_type new_size) { + resize(new_size, value_type()); } - // 销毁结点 - template - void list::destroy_node(node_ptr p) { - data_allocator::destroy(mystl::address_of(p->value)); - node_allocator::deallocate(p); + void resize(size_type new_size, const value_type& value); + + void swap(list& rhs) noexcept { + mystl::swap(node_, rhs.node_); + mystl::swap(size_, rhs.size_); } - // 用 n 个元素初始化容器 - template - void list::fill_init(size_type n, const value_type &value) { - node_ = base_allocator::allocate(1); - node_->unlink(); - size_ = n; - try { - for (; n > 0; --n) { - auto node = create_node(value); - link_nodes_at_back(node->as_base(), node->as_base()); - } - } catch (...) { - clear(); - base_allocator::deallocate(node_); - node_ = nullptr; - throw; - } + // list 相关操作 + + void splice(const_iterator pos, list& other); + void splice(const_iterator pos, list& other, const_iterator it); + void splice(const_iterator pos, list& other, const_iterator first, + const_iterator last); + + void remove(const value_type& value) { + remove_if([&](const value_type& v) { + return v == value; + }); } + template + void remove_if(UnaryPredicate pred); - // 以 [first, last) 初始化容器 - template - template - void list::copy_init(Iter first, Iter last) { - node_ = base_allocator::allocate(1); - node_->unlink(); - size_type n = mystl::distance(first, last); - size_ = n; - try { - for (; n > 0; --n, ++first) { - auto node = create_node(*first); - link_nodes_at_back(node->as_base(), node->as_base()); - } - } catch (...) { - clear(); - base_allocator::deallocate(node_); - node_ = nullptr; - throw; - } + void unique() { + unique(mystl::equal_to()); } + template + void unique(BinaryPredicate pred); - // 在 pos 处连接一个节点 - template - typename list::iterator list::link_iter_node(const_iterator pos, - base_ptr link_node) { - if (pos == node_->next) { - link_nodes_at_front(link_node, link_node); - } - else if (pos == node_) { - link_nodes_at_back(link_node, link_node); - } - else { - link_nodes(pos.node_, link_node, link_node); - } - return iterator(link_node); + void merge(list& x) { + merge(x, mystl::less()); + } + template + void merge(list& x, Compare comp); + + void sort() { + list_sort(begin(), end(), size(), mystl::less()); } - // 在 pos 处连接 [first, last] 的结点 - template - void list::link_nodes(base_ptr pos, base_ptr first, base_ptr last) { - pos->prev->next = first; - first->prev = pos->prev; - pos->prev = last; - last->next = pos; + template + void sort(Compared comp) { + list_sort(begin(), end(), size(), comp); } - // 在头部连接 [first, last] 结点 - template - void list::link_nodes_at_front(base_ptr first, base_ptr last) { - first->prev = node_; - last->next = node_->next; - last->next->prev = last; - node_->next = first; + void reverse(); + +private: + // helper functions + + // create / destroy node + template + node_ptr create_node(Args&&... agrs); + void destroy_node(node_ptr p); + + // initialize + void fill_init(size_type n, const value_type& value); + template + void copy_init(Iter first, Iter last); + + // link / unlink + iterator link_iter_node(const_iterator pos, base_ptr node); + void link_nodes(base_ptr p, base_ptr first, base_ptr last); + void link_nodes_at_front(base_ptr first, base_ptr last); + void link_nodes_at_back(base_ptr first, base_ptr last); + void unlink_nodes(base_ptr f, base_ptr l); + + // assign + void fill_assign(size_type n, const value_type& value); + template + void copy_assign(Iter first, Iter last); + + // insert + iterator + fill_insert(const_iterator pos, size_type n, const value_type& value); + template + iterator copy_insert(const_iterator pos, size_type n, Iter first); + + // sort + template + iterator + list_sort(iterator first, iterator last, size_type n, Compared comp); +}; + +/*****************************************************************************************/ + +// 删除 pos 处的元素 +template +typename list::iterator list::erase(const_iterator pos) { + MYSTL_DEBUG(pos != cend()); + auto n = pos.node_; + auto next = n->next; + unlink_nodes(n, n); + destroy_node(n->as_node()); + --size_; + return iterator(next); +} + +// 删除 [first, last) 内的元素 +template +typename list::iterator +list::erase(const_iterator first, const_iterator last) { + if (first != last) { + unlink_nodes(first.node_, last.node_->prev); + while (first != last) { + auto cur = first.node_; + ++first; + destroy_node(cur->as_node()); + --size_; + } + } + return iterator(last.node_); +} + +// 清空 list +template +void list::clear() { + if (size_ != 0) { + auto cur = node_->next; + for (base_ptr next = cur->next; cur != node_; + cur = next, next = cur->next) { + destroy_node(cur->as_node()); + } + node_->unlink(); + size_ = 0; + } +} + +// 重置容器大小 +template +void list::resize(size_type new_size, const value_type& value) { + auto i = begin(); + size_type len = 0; + while (i != end() && len < new_size) { + ++i; + ++len; } + if (len == new_size) { + erase(i, node_); + } + else { + insert(node_, new_size - len, value); + } +} + +// 将 list x 接合于 pos 之前 +template +void list::splice(const_iterator pos, list& x) { + MYSTL_DEBUG(this != &x); + if (!x.empty()) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, + "list's size too big"); - // 在尾部连接 [first, last] 结点 - template - void list::link_nodes_at_back(base_ptr first, base_ptr last) { - last->next = node_; - first->prev = node_->prev; - first->prev->next = first; - node_->prev = last; + auto f = x.node_->next; + auto l = x.node_->prev; + + x.unlink_nodes(f, l); + link_nodes(pos.node_, f, l); + + size_ += x.size_; + x.size_ = 0; } +} + +// 将 it 所指的节点接合于 pos 之前 +template +void list::splice(const_iterator pos, list& x, const_iterator it) { + if (pos.node_ != it.node_ && pos.node_ != it.node_->next) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); - // 容器与 [first, last] 结点断开连接 - template - void list::unlink_nodes(base_ptr first, base_ptr last) { - first->prev->next = last->next; - last->next->prev = first->prev; + auto f = it.node_; + + x.unlink_nodes(f, f); + link_nodes(pos.node_, f, f); + + ++size_; + --x.size_; } +} + +// 将 list x 的 [first, last) 内的节点接合于 pos 之前 +template +void list::splice(const_iterator pos, list& x, const_iterator first, + const_iterator last) { + if (first != last && this != &x) { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, "list's size too big"); + auto f = first.node_; + auto l = last.node_->prev; + + x.unlink_nodes(f, l); + link_nodes(pos.node_, f, l); - // 用 n 个元素为容器赋值 - template - void list::fill_assign(size_type n, const value_type &value) { - auto i = begin(); - auto e = end(); - for (; n > 0 && i != e; --n, ++i) { - *i = value; + size_ += n; + x.size_ -= n; + } +} + +// 将另一元操作 pred 为 true 的所有元素移除 +template +template +void list::remove_if(UnaryPredicate pred) { + auto f = begin(); + auto l = end(); + for (auto next = f; f != l; f = next) { + ++next; + if (pred(*f)) { + erase(f); } - if (n > 0) { - insert(e, n, value); + } +} + +// 移除 list 中满足 pred 为 true 重复元素 +template +template +void list::unique(BinaryPredicate pred) { + auto i = begin(); + auto e = end(); + auto j = i; + ++j; + while (j != e) { + if (pred(*i, *j)) { + erase(j); } else { - erase(i, e); + i = j; } + j = i; + ++j; } +} + +// 与另一个 list 合并,按照 comp 为 true 的顺序 +template +template +void list::merge(list& x, Compare comp) { + if (this != &x) { + THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, + "list's size too big"); - // 复制[f2, l2)为容器赋值 - template - template - void list::copy_assign(Iter f2, Iter l2) { auto f1 = begin(); auto l1 = end(); - for (; f1 != l1 && f2 != l2; ++f1, ++f2) { - *f1 = *f2; - } - if (f2 == l2) { - erase(f1, l1); + auto f2 = x.begin(); + auto l2 = x.end(); + + while (f1 != l1 && f2 != l2) { + if (comp(*f2, *f1)) { + // 使 comp 为 true 的一段区间 + auto next = f2; + ++next; + for (; next != l2 && comp(*next, *f1); ++next) + ; + auto f = f2.node_; + auto l = next.node_->prev; + f2 = next; + + // link node + x.unlink_nodes(f, l); + link_nodes(f1.node_, f, l); + ++f1; + } + else { + ++f1; + } } - else { - insert(l1, f2, l2); + // 连接剩余部分 + if (f2 != l2) { + auto f = f2.node_; + auto l = l2.node_->prev; + x.unlink_nodes(f, l); + link_nodes(l1.node_, f, l); } + + size_ += x.size_; + x.size_ = 0; } +} - // 在 pos 处插入 n 个元素 - template - typename list::iterator list::fill_insert(const_iterator pos, - size_type n, - const value_type &value) { - iterator r(pos.node_); - if (n != 0) { - const auto add_size = n; - auto node = create_node(value); - node->prev = nullptr; - r = iterator(node); - iterator end = r; - try { - // 前面已经创建了一个节点,还需 n - 1 个 - for (--n; n > 0; --n, ++end) { - auto next = create_node(value); - end.node_->next = next->as_base(); // link node - next->prev = end.node_; - } - size_ += add_size; - } catch (...) { - auto enode = end.node_; - while (true) { - auto prev = enode->prev; - destroy_node(enode->as_node()); - if (prev == nullptr) - break; - enode = prev; +// 将 list 反转 +template +void list::reverse() { + if (size_ <= 1) { + return; + } + auto i = begin(); + auto e = end(); + while (i.node_ != e.node_) { + mystl::swap(i.node_->prev, i.node_->next); + i.node_ = i.node_->prev; + } + mystl::swap(e.node_->prev, e.node_->next); +} + +/*****************************************************************************************/ +// helper function + +// 创建结点 +template +template +typename list::node_ptr list::create_node(Args&&... args) { + node_ptr p = node_allocator::allocate(1); + try { + data_allocator::construct(mystl::address_of(p->value), + mystl::forward(args)...); + p->prev = nullptr; + p->next = nullptr; + } catch (...) { + node_allocator::deallocate(p); + throw; + } + return p; +} + +// 销毁结点 +template +void list::destroy_node(node_ptr p) { + data_allocator::destroy(mystl::address_of(p->value)); + node_allocator::deallocate(p); +} + +// 用 n 个元素初始化容器 +template +void list::fill_init(size_type n, const value_type& value) { + node_ = base_allocator::allocate(1); + node_->unlink(); + size_ = n; + try { + for (; n > 0; --n) { + auto node = create_node(value); + link_nodes_at_back(node->as_base(), node->as_base()); + } + } catch (...) { + clear(); + base_allocator::deallocate(node_); + node_ = nullptr; + throw; + } +} + +// 以 [first, last) 初始化容器 +template +template +void list::copy_init(Iter first, Iter last) { + node_ = base_allocator::allocate(1); + node_->unlink(); + size_type n = mystl::distance(first, last); + size_ = n; + try { + for (; n > 0; --n, ++first) { + auto node = create_node(*first); + link_nodes_at_back(node->as_base(), node->as_base()); + } + } catch (...) { + clear(); + base_allocator::deallocate(node_); + node_ = nullptr; + throw; + } +} + +// 在 pos 处连接一个节点 +template +typename list::iterator +list::link_iter_node(const_iterator pos, base_ptr link_node) { + if (pos == node_->next) { + link_nodes_at_front(link_node, link_node); + } + else if (pos == node_) { + link_nodes_at_back(link_node, link_node); + } + else { + link_nodes(pos.node_, link_node, link_node); + } + return iterator(link_node); +} + +// 在 pos 处连接 [first, last] 的结点 +template +void list::link_nodes(base_ptr pos, base_ptr first, base_ptr last) { + pos->prev->next = first; + first->prev = pos->prev; + pos->prev = last; + last->next = pos; +} + +// 在头部连接 [first, last] 结点 +template +void list::link_nodes_at_front(base_ptr first, base_ptr last) { + first->prev = node_; + last->next = node_->next; + last->next->prev = last; + node_->next = first; +} + +// 在尾部连接 [first, last] 结点 +template +void list::link_nodes_at_back(base_ptr first, base_ptr last) { + last->next = node_; + first->prev = node_->prev; + first->prev->next = first; + node_->prev = last; +} + +// 容器与 [first, last] 结点断开连接 +template +void list::unlink_nodes(base_ptr first, base_ptr last) { + first->prev->next = last->next; + last->next->prev = first->prev; +} + +// 用 n 个元素为容器赋值 +template +void list::fill_assign(size_type n, const value_type& value) { + auto i = begin(); + auto e = end(); + for (; n > 0 && i != e; --n, ++i) { + *i = value; + } + if (n > 0) { + insert(e, n, value); + } + else { + erase(i, e); + } +} + +// 复制[f2, l2)为容器赋值 +template +template +void list::copy_assign(Iter f2, Iter l2) { + auto f1 = begin(); + auto l1 = end(); + for (; f1 != l1 && f2 != l2; ++f1, ++f2) { + *f1 = *f2; + } + if (f2 == l2) { + erase(f1, l1); + } + else { + insert(l1, f2, l2); + } +} + +// 在 pos 处插入 n 个元素 +template +typename list::iterator +list::fill_insert(const_iterator pos, size_type n, const value_type& value) { + iterator r(pos.node_); + if (n != 0) { + const auto add_size = n; + auto node = create_node(value); + node->prev = nullptr; + r = iterator(node); + iterator end = r; + try { + // 前面已经创建了一个节点,还需 n - 1 个 + for (--n; n > 0; --n, ++end) { + auto next = create_node(value); + end.node_->next = next->as_base(); // link node + next->prev = end.node_; + } + size_ += add_size; + } catch (...) { + auto enode = end.node_; + while (true) { + auto prev = enode->prev; + destroy_node(enode->as_node()); + if (prev == nullptr) { + break; } - throw; + enode = prev; } - link_nodes(pos.node_, r.node_, end.node_); + throw; } - return r; + link_nodes(pos.node_, r.node_, end.node_); } - - // 在 pos 处插入 [first, last) 的元素 - template - template - typename list::iterator list::copy_insert(const_iterator pos, - size_type n, Iter first) { - iterator r(pos.node_); - if (n != 0) { - const auto add_size = n; - auto node = create_node(*first); - node->prev = nullptr; - r = iterator(node); - iterator end = r; - try { - for (--n, ++first; n > 0; --n, ++first, ++end) { - auto next = create_node(*first); - end.node_->next = next->as_base(); // link node - next->prev = end.node_; - } - size_ += add_size; - } catch (...) { - auto enode = end.node_; - while (true) { - auto prev = enode->prev; - destroy_node(enode->as_node()); - if (prev == nullptr) - break; - enode = prev; + return r; +} + +// 在 pos 处插入 [first, last) 的元素 +template +template +typename list::iterator +list::copy_insert(const_iterator pos, size_type n, Iter first) { + iterator r(pos.node_); + if (n != 0) { + const auto add_size = n; + auto node = create_node(*first); + node->prev = nullptr; + r = iterator(node); + iterator end = r; + try { + for (--n, ++first; n > 0; --n, ++first, ++end) { + auto next = create_node(*first); + end.node_->next = next->as_base(); // link node + next->prev = end.node_; + } + size_ += add_size; + } catch (...) { + auto enode = end.node_; + while (true) { + auto prev = enode->prev; + destroy_node(enode->as_node()); + if (prev == nullptr) { + break; } - throw; + enode = prev; } - link_nodes(pos.node_, r.node_, end.node_); + throw; } - return r; + link_nodes(pos.node_, r.node_, end.node_); + } + return r; +} + +// 对 list 进行归并排序,返回一个迭代器指向区间最小元素的位置 +template +template +typename list::iterator +list::list_sort(iterator f1, iterator l2, size_type n, Compared comp) { + if (n < 2) { + return f1; } - // 对 list 进行归并排序,返回一个迭代器指向区间最小元素的位置 - template - template - typename list::iterator list::list_sort(iterator f1, iterator l2, - size_type n, Compared comp) { - if (n < 2) - return f1; - - if (n == 2) { - if (comp(*--l2, *f1)) { - auto ln = l2.node_; - unlink_nodes(ln, ln); - link_nodes(f1.node_, ln, ln); - return l2; - } - return f1; + if (n == 2) { + if (comp(*--l2, *f1)) { + auto ln = l2.node_; + unlink_nodes(ln, ln); + link_nodes(f1.node_, ln, ln); + return l2; } + return f1; + } - auto n2 = n / 2; - auto l1 = f1; - mystl::advance(l1, n2); - auto result = f1 = list_sort(f1, l1, n2, comp); // 前半段的最小位置 - auto f2 = l1 = list_sort(l1, l2, n - n2, comp); // 后半段的最小位置 + auto n2 = n / 2; + auto l1 = f1; + mystl::advance(l1, n2); + auto result = f1 = list_sort(f1, l1, n2, comp); // 前半段的最小位置 + auto f2 = l1 = list_sort(l1, l2, n - n2, comp); // 后半段的最小位置 + + // 把较小的一段区间移到前面 + if (comp(*f2, *f1)) { + auto m = f2; + ++m; + for (; m != l2 && comp(*m, *f1); ++m) + ; + auto f = f2.node_; + auto l = m.node_->prev; + result = f2; + l1 = f2 = m; + unlink_nodes(f, l); + m = f1; + ++m; + link_nodes(f1.node_, f, l); + f1 = m; + } + else { + ++f1; + } - // 把较小的一段区间移到前面 + // 合并两段有序区间 + while (f1 != l1 && f2 != l2) { if (comp(*f2, *f1)) { auto m = f2; ++m; @@ -1064,8 +1116,10 @@ namespace mystl { ; auto f = f2.node_; auto l = m.node_->prev; - result = f2; - l1 = f2 = m; + if (l1 == f2) { + l1 = m; + } + f2 = m; unlink_nodes(f, l); m = f1; ++m; @@ -1075,76 +1129,54 @@ namespace mystl { else { ++f1; } - - // 合并两段有序区间 - while (f1 != l1 && f2 != l2) { - if (comp(*f2, *f1)) { - auto m = f2; - ++m; - for (; m != l2 && comp(*m, *f1); ++m) - ; - auto f = f2.node_; - auto l = m.node_->prev; - if (l1 == f2) - l1 = m; - f2 = m; - unlink_nodes(f, l); - m = f1; - ++m; - link_nodes(f1.node_, f, l); - f1 = m; - } - else { - ++f1; - } - } - return result; - } - - // 重载比较操作符 - template - bool operator==(const list &lhs, const list &rhs) { - auto f1 = lhs.cbegin(); - auto f2 = rhs.cbegin(); - auto l1 = lhs.cend(); - auto l2 = rhs.cend(); - for (; f1 != l1 && f2 != l2 && *f1 == *f2; ++f1, ++f2) - ; - return f1 == l1 && f2 == l2; - } - - template - bool operator<(const list &lhs, const list &rhs) { - return mystl::lexicographical_compare(lhs.cbegin(), lhs.cend(), - rhs.cbegin(), rhs.cend()); - } - - template - bool operator!=(const list &lhs, const list &rhs) { - return !(lhs == rhs); - } - - template - bool operator>(const list &lhs, const list &rhs) { - return rhs < lhs; - } - - template - bool operator<=(const list &lhs, const list &rhs) { - return !(rhs < lhs); - } - - template - bool operator>=(const list &lhs, const list &rhs) { - return !(lhs < rhs); - } - - // 重载 mystl 的 swap - template - void swap(list &lhs, list &rhs) noexcept { - lhs.swap(rhs); } - -}; - -#endif /* _LIST_ */ + return result; +} + +// 重载比较操作符 +template +bool operator==(const list& lhs, const list& rhs) { + auto f1 = lhs.cbegin(); + auto f2 = rhs.cbegin(); + auto l1 = lhs.cend(); + auto l2 = rhs.cend(); + for (; f1 != l1 && f2 != l2 && *f1 == *f2; ++f1, ++f2) + ; + return f1 == l1 && f2 == l2; +} + +template +bool operator<(const list& lhs, const list& rhs) { + return mystl::lexicographical_compare(lhs.cbegin(), lhs.cend(), + rhs.cbegin(), rhs.cend()); +} + +template +bool operator!=(const list& lhs, const list& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const list& lhs, const list& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const list& lhs, const list& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const list& lhs, const list& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(list& lhs, list& rhs) noexcept { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_LIST */ diff --git a/src/libcxx/include/map b/src/libcxx/include/map index 866e9f086..571f52b51 100644 --- a/src/libcxx/include/map +++ b/src/libcxx/include/map @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// map for Simple-XX/SimpleKernel. - -#ifndef _MAP_ -#define _MAP_ +/** + * @file map + * @brief stl map 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_MAP +#define SIMPLEKERNEL_MAP // 这个头文件包含了两个模板类 map 和 multimap // map : 映射,元素具有键值和实值,会根据键值大小自动排序,键值不允许重复 @@ -24,613 +35,660 @@ namespace mystl { - // 模板类 map,键值不允许重复 - // 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 - // mystl::less - template > - class map { - public: - // map 的嵌套型别定义 - typedef Key key_type; - typedef T mapped_type; - typedef mystl::pair value_type; - typedef Compare key_compare; - - // 定义一个 functor,用来进行元素比较 - class value_compare - : public binary_function { - friend class map; - - private: - Compare comp; - value_compare(Compare c) : comp(c) { - } - - public: - bool operator()(const value_type &lhs, - const value_type &rhs) const { - return comp(lhs.first, rhs.first); // 比较键值的大小 - } - }; +// 模板类 map,键值不允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 +// mystl::less +template > +class map { +public: + // map 的嵌套型别定义 + typedef Key key_type; + typedef T mapped_type; + typedef mystl::pair value_type; + typedef Compare key_compare; + + // 定义一个 functor,用来进行元素比较 + class value_compare : public binary_function { + friend class map; private: - // 以 mystl::rb_tree 作为底层机制 - typedef mystl::rb_tree base_type; - base_type tree_; + Compare comp; - public: - // 使用 rb_tree 的型别 - typedef typename base_type::node_type node_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; - typedef typename base_type::iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::reverse_iterator reverse_iterator; - typedef - typename base_type::const_reverse_iterator const_reverse_iterator; - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::allocator_type allocator_type; + value_compare(Compare c) : comp(c) { + } public: - // 构造、复制、移动、赋值函数 + bool operator()(const value_type& lhs, const value_type& rhs) const { + return comp(lhs.first, rhs.first); // 比较键值的大小 + } + }; - map() = default; +private: + // 以 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; + +public: + // 使用 rb_tree 的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动、赋值函数 + + map() = default; + + template + map(InputIterator first, InputIterator last) : tree_() { + tree_.insert_unique(first, last); + } - template - map(InputIterator first, InputIterator last) : tree_() { - tree_.insert_unique(first, last); - } + map(std::initializer_list ilist) : tree_() { + tree_.insert_unique(ilist.begin(), ilist.end()); + } - map(std::initializer_list ilist) : tree_() { - tree_.insert_unique(ilist.begin(), ilist.end()); - } + map(const map& rhs) : tree_(rhs.tree_) { + } - map(const map &rhs) : tree_(rhs.tree_) { - } - map(map &&rhs) noexcept : tree_(mystl::move(rhs.tree_)) { - } + map(map&& rhs) noexcept : tree_(mystl::move(rhs.tree_)) { + } - map &operator=(const map &rhs) { - tree_ = rhs.tree_; - return *this; - } - map &operator=(map &&rhs) { - tree_ = mystl::move(rhs.tree_); - return *this; - } + map& operator=(const map& rhs) { + tree_ = rhs.tree_; + return *this; + } - map &operator=(std::initializer_list ilist) { - tree_.clear(); - tree_.insert_unique(ilist.begin(), ilist.end()); - return *this; - } + map& operator=(map&& rhs) { + tree_ = mystl::move(rhs.tree_); + return *this; + } - // 相关接口 + map& operator=(std::initializer_list ilist) { + tree_.clear(); + tree_.insert_unique(ilist.begin(), ilist.end()); + return *this; + } - key_compare key_comp() const { - return tree_.key_comp(); - } - value_compare value_comp() const { - return value_compare(tree_.key_comp()); - } - allocator_type get_allocator() const { - return tree_.get_allocator(); - } + // 相关接口 - // 迭代器相关 + key_compare key_comp() const { + return tree_.key_comp(); + } - iterator begin() noexcept { - return tree_.begin(); - } - const_iterator begin() const noexcept { - return tree_.begin(); - } - iterator end() noexcept { - return tree_.end(); - } - const_iterator end() const noexcept { - return tree_.end(); - } + value_compare value_comp() const { + return value_compare(tree_.key_comp()); + } - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } + allocator_type get_allocator() const { + return tree_.get_allocator(); + } - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } + // 迭代器相关 - // 容量相关 - bool empty() const noexcept { - return tree_.empty(); - } - size_type size() const noexcept { - return tree_.size(); - } - size_type max_size() const noexcept { - return tree_.max_size(); - } + iterator begin() noexcept { + return tree_.begin(); + } - // 访问元素相关 + const_iterator begin() const noexcept { + return tree_.begin(); + } - // 若键值不存在,at 会抛出一个异常 - mapped_type &at(const key_type &key) { - iterator it = lower_bound(key); - // it->first >= key - THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key), - "map no such element exists"); - return it->second; - } - const mapped_type &at(const key_type &key) const { - const_iterator it = lower_bound(key); - // it->first >= key - THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key), - "map no such element exists"); - return it->second; - } + iterator end() noexcept { + return tree_.end(); + } - mapped_type &operator[](const key_type &key) { - iterator it = lower_bound(key); - // it->first >= key - if (it == end() || key_comp()(key, it->first)) - it = emplace_hint(it, key, T{}); - return it->second; - } - mapped_type &operator[](key_type &&key) { - iterator it = lower_bound(key); - // it->first >= key - if (it == end() || key_comp()(key, it->first)) - it = emplace_hint(it, mystl::move(key), T{}); - return it->second; - } + const_iterator end() const noexcept { + return tree_.end(); + } - // 插入删除相关 + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } - template - pair emplace(Args &&...args) { - return tree_.emplace_unique(mystl::forward(args)...); - } + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } - template - iterator emplace_hint(iterator hint, Args &&...args) { - return tree_.emplace_unique_use_hint(hint, - mystl::forward(args)...); - } + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - pair insert(const value_type &value) { - return tree_.insert_unique(value); - } - pair insert(value_type &&value) { - return tree_.insert_unique(mystl::move(value)); - } + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - iterator insert(iterator hint, const value_type &value) { - return tree_.insert_unique(hint, value); - } - iterator insert(iterator hint, value_type &&value) { - return tree_.insert_unique(hint, mystl::move(value)); - } + const_iterator cbegin() const noexcept { + return begin(); + } - template - void insert(InputIterator first, InputIterator last) { - tree_.insert_unique(first, last); - } + const_iterator cend() const noexcept { + return end(); + } - void erase(iterator position) { - tree_.erase(position); - } - size_type erase(const key_type &key) { - return tree_.erase_unique(key); - } - void erase(iterator first, iterator last) { - tree_.erase(first, last); - } + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } - void clear() { - tree_.clear(); - } + const_reverse_iterator crend() const noexcept { + return rend(); + } - // map 相关操作 + // 容量相关 + bool empty() const noexcept { + return tree_.empty(); + } - iterator find(const key_type &key) { - return tree_.find(key); - } - const_iterator find(const key_type &key) const { - return tree_.find(key); - } + size_type size() const noexcept { + return tree_.size(); + } - size_type count(const key_type &key) const { - return tree_.count_unique(key); - } + size_type max_size() const noexcept { + return tree_.max_size(); + } - iterator lower_bound(const key_type &key) { - return tree_.lower_bound(key); - } - const_iterator lower_bound(const key_type &key) const { - return tree_.lower_bound(key); - } + // 访问元素相关 - iterator upper_bound(const key_type &key) { - return tree_.upper_bound(key); - } - const_iterator upper_bound(const key_type &key) const { - return tree_.upper_bound(key); - } + // 若键值不存在,at 会抛出一个异常 + mapped_type& at(const key_type& key) { + iterator it = lower_bound(key); + // it->first >= key + THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key), + "map no such element exists"); + return it->second; + } - pair equal_range(const key_type &key) { - return tree_.equal_range_unique(key); + const mapped_type& at(const key_type& key) const { + const_iterator it = lower_bound(key); + // it->first >= key + THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key), + "map no such element exists"); + return it->second; + } + + mapped_type& operator[](const key_type& key) { + iterator it = lower_bound(key); + // it->first >= key + if (it == end() || key_comp()(key, it->first)) { + it = emplace_hint(it, key, T {}); } + return it->second; + } - pair - equal_range(const key_type &key) const { - return tree_.equal_range_unique(key); + mapped_type& operator[](key_type&& key) { + iterator it = lower_bound(key); + // it->first >= key + if (it == end() || key_comp()(key, it->first)) { + it = emplace_hint(it, mystl::move(key), T {}); } + return it->second; + } + + // 插入删除相关 + + template + pair emplace(Args&&... args) { + return tree_.emplace_unique(mystl::forward(args)...); + } - void swap(map &rhs) noexcept { - tree_.swap(rhs.tree_); + template + iterator emplace_hint(iterator hint, Args&&... args) { + return tree_.emplace_unique_use_hint(hint, + mystl::forward(args)...); + } + + pair insert(const value_type& value) { + return tree_.insert_unique(value); + } + + pair insert(value_type&& value) { + return tree_.insert_unique(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) { + return tree_.insert_unique(hint, value); + } + + iterator insert(iterator hint, value_type&& value) { + return tree_.insert_unique(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) { + tree_.insert_unique(first, last); + } + + void erase(iterator position) { + tree_.erase(position); + } + + size_type erase(const key_type& key) { + return tree_.erase_unique(key); + } + + void erase(iterator first, iterator last) { + tree_.erase(first, last); + } + + void clear() { + tree_.clear(); + } + + // map 相关操作 + + iterator find(const key_type& key) { + return tree_.find(key); + } + + const_iterator find(const key_type& key) const { + return tree_.find(key); + } + + size_type count(const key_type& key) const { + return tree_.count_unique(key); + } + + iterator lower_bound(const key_type& key) { + return tree_.lower_bound(key); + } + + const_iterator lower_bound(const key_type& key) const { + return tree_.lower_bound(key); + } + + iterator upper_bound(const key_type& key) { + return tree_.upper_bound(key); + } + + const_iterator upper_bound(const key_type& key) const { + return tree_.upper_bound(key); + } + + pair equal_range(const key_type& key) { + return tree_.equal_range_unique(key); + } + + pair + equal_range(const key_type& key) const { + return tree_.equal_range_unique(key); + } + + void swap(map& rhs) noexcept { + tree_.swap(rhs.tree_); + } + +public: + friend bool operator==(const map& lhs, const map& rhs) { + return lhs.tree_ == rhs.tree_; + } + + friend bool operator<(const map& lhs, const map& rhs) { + return lhs.tree_ < rhs.tree_; + } +}; + +// 重载比较操作符 +template +bool operator==(const map& lhs, + const map& rhs) { + return lhs == rhs; +} + +template +bool operator<(const map& lhs, + const map& rhs) { + return lhs < rhs; +} + +template +bool operator!=(const map& lhs, + const map& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const map& lhs, + const map& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const map& lhs, + const map& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const map& lhs, + const map& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(map& lhs, map& rhs) noexcept { + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 multimap,键值允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 +// mystl::less +template > +class multimap { +public: + // multimap 的型别定义 + typedef Key key_type; + typedef T mapped_type; + typedef mystl::pair value_type; + typedef Compare key_compare; + + // 定义一个 functor,用来进行元素比较 + class value_compare : public binary_function { + friend class multimap; + + private: + Compare comp; + + value_compare(Compare c) : comp(c) { } public: - friend bool operator==(const map &lhs, const map &rhs) { - return lhs.tree_ == rhs.tree_; - } - friend bool operator<(const map &lhs, const map &rhs) { - return lhs.tree_ < rhs.tree_; + bool operator()(const value_type& lhs, const value_type& rhs) const { + return comp(lhs.first, rhs.first); } }; - // 重载比较操作符 - template - bool operator==(const map &lhs, - const map &rhs) { - return lhs == rhs; +private: + // 用 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; + +public: + // 使用 rb_tree 的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动函数 + + multimap() = default; + + template + multimap(InputIterator first, InputIterator last) : tree_() { + tree_.insert_multi(first, last); } - template - bool operator<(const map &lhs, - const map &rhs) { - return lhs < rhs; + multimap(std::initializer_list ilist) : tree_() { + tree_.insert_multi(ilist.begin(), ilist.end()); } - template - bool operator!=(const map &lhs, - const map &rhs) { - return !(lhs == rhs); + multimap(const multimap& rhs) : tree_(rhs.tree_) { } - template - bool operator>(const map &lhs, - const map &rhs) { - return rhs < lhs; + multimap(multimap&& rhs) noexcept : tree_(mystl::move(rhs.tree_)) { } - template - bool operator<=(const map &lhs, - const map &rhs) { - return !(rhs < lhs); + multimap& operator=(const multimap& rhs) { + tree_ = rhs.tree_; + return *this; } - template - bool operator>=(const map &lhs, - const map &rhs) { - return !(lhs < rhs); + multimap& operator=(multimap&& rhs) { + tree_ = mystl::move(rhs.tree_); + return *this; } - // 重载 mystl 的 swap - template - void swap(map &lhs, map &rhs) noexcept { - lhs.swap(rhs); + multimap& operator=(std::initializer_list ilist) { + tree_.clear(); + tree_.insert_multi(ilist.begin(), ilist.end()); + return *this; } - /*****************************************************************************************/ + // 相关接口 - // 模板类 multimap,键值允许重复 - // 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 - // mystl::less - template > - class multimap { - public: - // multimap 的型别定义 - typedef Key key_type; - typedef T mapped_type; - typedef mystl::pair value_type; - typedef Compare key_compare; - - // 定义一个 functor,用来进行元素比较 - class value_compare - : public binary_function { - friend class multimap; - - private: - Compare comp; - value_compare(Compare c) : comp(c) { - } - - public: - bool operator()(const value_type &lhs, - const value_type &rhs) const { - return comp(lhs.first, rhs.first); - } - }; + key_compare key_comp() const { + return tree_.key_comp(); + } - private: - // 用 mystl::rb_tree 作为底层机制 - typedef mystl::rb_tree base_type; - base_type tree_; + value_compare value_comp() const { + return value_compare(tree_.key_comp()); + } - public: - // 使用 rb_tree 的型别 - typedef typename base_type::node_type node_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; - typedef typename base_type::iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::reverse_iterator reverse_iterator; - typedef - typename base_type::const_reverse_iterator const_reverse_iterator; - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::allocator_type allocator_type; + allocator_type get_allocator() const { + return tree_.get_allocator(); + } - public: - // 构造、复制、移动函数 + // 迭代器相关 - multimap() = default; + iterator begin() noexcept { + return tree_.begin(); + } - template - multimap(InputIterator first, InputIterator last) : tree_() { - tree_.insert_multi(first, last); - } - multimap(std::initializer_list ilist) : tree_() { - tree_.insert_multi(ilist.begin(), ilist.end()); - } + const_iterator begin() const noexcept { + return tree_.begin(); + } - multimap(const multimap &rhs) : tree_(rhs.tree_) { - } - multimap(multimap &&rhs) noexcept : tree_(mystl::move(rhs.tree_)) { - } + iterator end() noexcept { + return tree_.end(); + } - multimap &operator=(const multimap &rhs) { - tree_ = rhs.tree_; - return *this; - } - multimap &operator=(multimap &&rhs) { - tree_ = mystl::move(rhs.tree_); - return *this; - } + const_iterator end() const noexcept { + return tree_.end(); + } - multimap &operator=(std::initializer_list ilist) { - tree_.clear(); - tree_.insert_multi(ilist.begin(), ilist.end()); - return *this; - } + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } - // 相关接口 + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } - key_compare key_comp() const { - return tree_.key_comp(); - } - value_compare value_comp() const { - return value_compare(tree_.key_comp()); - } - allocator_type get_allocator() const { - return tree_.get_allocator(); - } + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - // 迭代器相关 + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - iterator begin() noexcept { - return tree_.begin(); - } - const_iterator begin() const noexcept { - return tree_.begin(); - } - iterator end() noexcept { - return tree_.end(); - } - const_iterator end() const noexcept { - return tree_.end(); - } + const_iterator cbegin() const noexcept { + return begin(); + } - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } + const_iterator cend() const noexcept { + return end(); + } - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } - // 容量相关 - bool empty() const noexcept { - return tree_.empty(); - } - size_type size() const noexcept { - return tree_.size(); - } - size_type max_size() const noexcept { - return tree_.max_size(); - } + const_reverse_iterator crend() const noexcept { + return rend(); + } - // 插入删除操作 + // 容量相关 + bool empty() const noexcept { + return tree_.empty(); + } - template - iterator emplace(Args &&...args) { - return tree_.emplace_multi(mystl::forward(args)...); - } + size_type size() const noexcept { + return tree_.size(); + } - template - iterator emplace_hint(iterator hint, Args &&...args) { - return tree_.emplace_multi_use_hint(hint, - mystl::forward(args)...); - } + size_type max_size() const noexcept { + return tree_.max_size(); + } - iterator insert(const value_type &value) { - return tree_.insert_multi(value); - } - iterator insert(value_type &&value) { - return tree_.insert_multi(mystl::move(value)); - } + // 插入删除操作 - iterator insert(iterator hint, const value_type &value) { - return tree_.insert_multi(hint, value); - } - iterator insert(iterator hint, value_type &&value) { - return tree_.insert_multi(hint, mystl::move(value)); - } + template + iterator emplace(Args&&... args) { + return tree_.emplace_multi(mystl::forward(args)...); + } - template - void insert(InputIterator first, InputIterator last) { - tree_.insert_multi(first, last); - } + template + iterator emplace_hint(iterator hint, Args&&... args) { + return tree_.emplace_multi_use_hint(hint, + mystl::forward(args)...); + } - void erase(iterator position) { - tree_.erase(position); - } - size_type erase(const key_type &key) { - return tree_.erase_multi(key); - } - void erase(iterator first, iterator last) { - tree_.erase(first, last); - } + iterator insert(const value_type& value) { + return tree_.insert_multi(value); + } - void clear() { - tree_.clear(); - } + iterator insert(value_type&& value) { + return tree_.insert_multi(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) { + return tree_.insert_multi(hint, value); + } - // multimap 相关操作 + iterator insert(iterator hint, value_type&& value) { + return tree_.insert_multi(hint, mystl::move(value)); + } - iterator find(const key_type &key) { - return tree_.find(key); - } - const_iterator find(const key_type &key) const { - return tree_.find(key); - } + template + void insert(InputIterator first, InputIterator last) { + tree_.insert_multi(first, last); + } - size_type count(const key_type &key) const { - return tree_.count_multi(key); - } + void erase(iterator position) { + tree_.erase(position); + } - iterator lower_bound(const key_type &key) { - return tree_.lower_bound(key); - } - const_iterator lower_bound(const key_type &key) const { - return tree_.lower_bound(key); - } + size_type erase(const key_type& key) { + return tree_.erase_multi(key); + } - iterator upper_bound(const key_type &key) { - return tree_.upper_bound(key); - } - const_iterator upper_bound(const key_type &key) const { - return tree_.upper_bound(key); - } + void erase(iterator first, iterator last) { + tree_.erase(first, last); + } - pair equal_range(const key_type &key) { - return tree_.equal_range_multi(key); - } + void clear() { + tree_.clear(); + } - pair - equal_range(const key_type &key) const { - return tree_.equal_range_multi(key); - } + // multimap 相关操作 - void swap(multimap &rhs) noexcept { - tree_.swap(rhs.tree_); - } + iterator find(const key_type& key) { + return tree_.find(key); + } - public: - friend bool operator==(const multimap &lhs, const multimap &rhs) { - return lhs.tree_ == rhs.tree_; - } - friend bool operator<(const multimap &lhs, const multimap &rhs) { - return lhs.tree_ < rhs.tree_; - } - }; + const_iterator find(const key_type& key) const { + return tree_.find(key); + } + + size_type count(const key_type& key) const { + return tree_.count_multi(key); + } - // 重载比较操作符 - template - bool operator==(const multimap &lhs, - const multimap &rhs) { - return lhs == rhs; + iterator lower_bound(const key_type& key) { + return tree_.lower_bound(key); } - template - bool operator<(const multimap &lhs, - const multimap &rhs) { - return lhs < rhs; + const_iterator lower_bound(const key_type& key) const { + return tree_.lower_bound(key); } - template - bool operator!=(const multimap &lhs, - const multimap &rhs) { - return !(lhs == rhs); + iterator upper_bound(const key_type& key) { + return tree_.upper_bound(key); } - template - bool operator>(const multimap &lhs, - const multimap &rhs) { - return rhs < lhs; + const_iterator upper_bound(const key_type& key) const { + return tree_.upper_bound(key); } - template - bool operator<=(const multimap &lhs, - const multimap &rhs) { - return !(rhs < lhs); + pair equal_range(const key_type& key) { + return tree_.equal_range_multi(key); } - template - bool operator>=(const multimap &lhs, - const multimap &rhs) { - return !(lhs < rhs); + pair + equal_range(const key_type& key) const { + return tree_.equal_range_multi(key); } - // 重载 mystl 的 swap - template - void swap(multimap &lhs, - multimap &rhs) noexcept { - lhs.swap(rhs); + void swap(multimap& rhs) noexcept { + tree_.swap(rhs.tree_); } +public: + friend bool operator==(const multimap& lhs, const multimap& rhs) { + return lhs.tree_ == rhs.tree_; + } + + friend bool operator<(const multimap& lhs, const multimap& rhs) { + return lhs.tree_ < rhs.tree_; + } }; -#endif /* _MAP_ */ +// 重载比较操作符 +template +bool operator==(const multimap& lhs, + const multimap& rhs) { + return lhs == rhs; +} + +template +bool operator<(const multimap& lhs, + const multimap& rhs) { + return lhs < rhs; +} + +template +bool operator!=(const multimap& lhs, + const multimap& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const multimap& lhs, + const multimap& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const multimap& lhs, + const multimap& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const multimap& lhs, + const multimap& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(multimap& lhs, + multimap& rhs) noexcept { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_MAP */ diff --git a/src/libcxx/include/memory b/src/libcxx/include/memory index 97f2d60f9..059eb9e53 100644 --- a/src/libcxx/include/memory +++ b/src/libcxx/include/memory @@ -1,211 +1,234 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// memory for Simple-XX/SimpleKernel. - -#ifndef _MEMORY_ -#define _MEMORY_ +/** + * @file memory + * @brief stl memory 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_MEMORY +#define SIMPLEKERNEL_MEMORY // 这个头文件负责更高级的动态内存管理 // 包含一些基本函数、空间配置器、未初始化的储存空间管理,以及一个模板类 auto_ptr -#include "stddef.h" -#include "stdlib.h" -#include "limits.h" #include "algobase" #include "allocator" #include "construct" +#include "limits.h" +#include "stddef.h" +#include "stdlib.h" #include "uninitialized" namespace mystl { - // 获取对象地址 - template - constexpr Tp *address_of(Tp &value) noexcept { - return &value; - } +// 获取对象地址 +template +constexpr Tp* address_of(Tp& value) noexcept { + return &value; +} - // 获取 / 释放 临时缓冲区 +// 获取 / 释放 临时缓冲区 - template - pair get_buffer_helper(ptrdiff_t len, T *) { - if (len > static_cast(INT_MAX / sizeof(T))) - len = INT_MAX / sizeof(T); - while (len > 0) { - T *tmp = - static_cast(malloc(static_cast(len) * sizeof(T))); - if (tmp) - return pair(tmp, len); - len /= 2; // 申请失败时减少 len 的大小 +template +pair get_buffer_helper(ptrdiff_t len, T*) { + if (len > static_cast(INT_MAX / sizeof(T))) { + len = INT_MAX / sizeof(T); + } + while (len > 0) { + T* tmp = static_cast(kmalloc(static_cast(len) * sizeof(T))); + if (tmp) { + return pair(tmp, len); } - return pair(nullptr, 0); + len /= 2; // 申请失败时减少 len 的大小 + } + return pair(nullptr, 0); +} + +template +pair get_temporary_buffer(ptrdiff_t len) { + return get_buffer_helper(len, static_cast(0)); +} + +template +pair get_temporary_buffer(ptrdiff_t len, T*) { + return get_buffer_helper(len, static_cast(0)); +} + +template +void release_temporary_buffer(T* ptr) { + kfree(ptr); +} + +// -------------------------------------------------------------------------------------- +// 类模板 : temporary_buffer +// 进行临时缓冲区的申请与释放 +template +class temporary_buffer { +private: + ptrdiff_t original_len; // 缓冲区申请的大小 + ptrdiff_t len; // 缓冲区实际的大小 + T* buffer; // 指向缓冲区的指针 + +public: + // 构造、析构函数 + temporary_buffer(ForwardIterator first, ForwardIterator last); + + ~temporary_buffer() { + mystl::destroy(buffer, buffer + len); + kfree(buffer); } - template - pair get_temporary_buffer(ptrdiff_t len) { - return get_buffer_helper(len, static_cast(0)); +public: + ptrdiff_t size() const noexcept { + return len; } - template - pair get_temporary_buffer(ptrdiff_t len, T *) { - return get_buffer_helper(len, static_cast(0)); + ptrdiff_t requested_size() const noexcept { + return original_len; } - template - void release_temporary_buffer(T *ptr) { - free(ptr); + T* begin() noexcept { + return buffer; } - // -------------------------------------------------------------------------------------- - // 类模板 : temporary_buffer - // 进行临时缓冲区的申请与释放 - template - class temporary_buffer { - private: - ptrdiff_t original_len; // 缓冲区申请的大小 - ptrdiff_t len; // 缓冲区实际的大小 - T * buffer; // 指向缓冲区的指针 + T* end() noexcept { + return buffer + len; + } - public: - // 构造、析构函数 - temporary_buffer(ForwardIterator first, ForwardIterator last); +private: + void allocate_buffer(); - ~temporary_buffer() { - mystl::destroy(buffer, buffer + len); - free(buffer); - } + void initialize_buffer(const T&, std::true_type) { + } - public: - ptrdiff_t size() const noexcept { - return len; - } - ptrdiff_t requested_size() const noexcept { - return original_len; - } - T *begin() noexcept { - return buffer; - } - T *end() noexcept { - return buffer + len; - } + void initialize_buffer(const T& value, std::false_type) { + mystl::uninitialized_fill_n(buffer, len, value); + } - private: - void allocate_buffer(); - void initialize_buffer(const T &, std::true_type) { - } - void initialize_buffer(const T &value, std::false_type) { - mystl::uninitialized_fill_n(buffer, len, value); - } +private: + temporary_buffer(const temporary_buffer&); + void operator=(const temporary_buffer&); +}; - private: - temporary_buffer(const temporary_buffer &); - void operator=(const temporary_buffer &); - }; - - // 构造函数 - template - temporary_buffer::temporary_buffer( - ForwardIterator first, ForwardIterator last) { - try { - len = mystl::distance(first, last); - allocate_buffer(); - if (len > 0) { - initialize_buffer(*first, - std::is_trivially_default_constructible()); - } - } catch (...) { - free(buffer); - buffer = nullptr; - len = 0; - } +// 构造函数 +template +temporary_buffer::temporary_buffer(ForwardIterator first, + ForwardIterator last) { + try { + len = mystl::distance(first, last); + allocate_buffer(); + if (len > 0) { + initialize_buffer(*first, + std::is_trivially_default_constructible()); + } + } catch (...) { + kfree(buffer); + buffer = nullptr; + len = 0; } - - // allocate_buffer 函数 - template - void temporary_buffer::allocate_buffer() { - original_len = len; - if (len > static_cast(INT_MAX / sizeof(T))) - len = INT_MAX / sizeof(T); - while (len > 0) { - buffer = static_cast(malloc(len * sizeof(T))); - if (buffer) - break; - len /= 2; // 申请失败时减少申请空间大小 +} + +// allocate_buffer 函数 +template +void temporary_buffer::allocate_buffer() { + original_len = len; + if (len > static_cast(INT_MAX / sizeof(T))) { + len = INT_MAX / sizeof(T); + } + while (len > 0) { + buffer = static_cast(kmalloc(len * sizeof(T))); + if (buffer) { + break; } + len /= 2; // 申请失败时减少申请空间大小 + } +} + +// -------------------------------------------------------------------------------------- +// 模板类: auto_ptr +// 一个具有严格对象所有权的小型智能指针 +template +class auto_ptr { +public: + typedef T elem_type; + +private: + T* m_ptr; // 实际指针 + +public: + // 构造、复制、析构函数 + explicit auto_ptr(T* p = nullptr) : m_ptr(p) { } - // -------------------------------------------------------------------------------------- - // 模板类: auto_ptr - // 一个具有严格对象所有权的小型智能指针 - template - class auto_ptr { - public: - typedef T elem_type; - - private: - T *m_ptr; // 实际指针 + auto_ptr(auto_ptr& rhs) : m_ptr(rhs.release()) { + } - public: - // 构造、复制、析构函数 - explicit auto_ptr(T *p = nullptr) : m_ptr(p) { - } - auto_ptr(auto_ptr &rhs) : m_ptr(rhs.release()) { - } - template - auto_ptr(auto_ptr &rhs) : m_ptr(rhs.release()) { - } + template + auto_ptr(auto_ptr& rhs) : m_ptr(rhs.release()) { + } - auto_ptr &operator=(auto_ptr &rhs) { - if (this != &rhs) { - delete m_ptr; - m_ptr = rhs.release(); - } - return *this; - } - template - auto_ptr &operator=(auto_ptr &rhs) { - if (this->get() != rhs.get()) { - delete m_ptr; - m_ptr = rhs.release(); - } - return *this; + auto_ptr& operator=(auto_ptr& rhs) { + if (this != &rhs) { + delete m_ptr; + m_ptr = rhs.release(); } + return *this; + } - ~auto_ptr() { + template + auto_ptr& operator=(auto_ptr& rhs) { + if (this->get() != rhs.get()) { delete m_ptr; + m_ptr = rhs.release(); } + return *this; + } - public: - // 重载 operator* 和 operator-> - T &operator*() const { - return *m_ptr; - } - T *operator->() const { - return m_ptr; - } + ~auto_ptr() { + delete m_ptr; + } - // 获得指针 - T *get() const { - return m_ptr; - } +public: + // 重载 operator* 和 operator-> + T& operator*() const { + return *m_ptr; + } - // 释放指针 - T *release() { - T *tmp = m_ptr; - m_ptr = nullptr; - return tmp; - } + T* operator->() const { + return m_ptr; + } - // 重置指针 - void reset(T *p = nullptr) { - if (m_ptr != p) { - delete m_ptr; - m_ptr = p; - } - } - }; + // 获得指针 + T* get() const { + return m_ptr; + } + // 释放指针 + T* release() { + T* tmp = m_ptr; + m_ptr = nullptr; + return tmp; + } + + // 重置指针 + void reset(T* p = nullptr) { + if (m_ptr != p) { + delete m_ptr; + m_ptr = p; + } + } }; -#endif /* _MEMORY_ */ +}; // namespace mystl + +#endif /* SIMPLEKERNEL_MEMORY */ diff --git a/src/libcxx/include/new b/src/libcxx/include/new index f8106cd25..f83f429b5 100644 --- a/src/libcxx/include/new +++ b/src/libcxx/include/new @@ -1,43 +1,54 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// new for Simple-XX/SimpleKernel. - -#ifndef _NEW_ -#define _NEW_ - -#include "stddef.h" +/** + * @file new + * @brief 内存分配 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_NEW +#define SIMPLEKERNEL_NEW + +#include "cstddef" namespace std { - enum class align_val_t : size_t {}; +enum class align_val_t : size_t { }; +}; // namespace std -void *operator new(size_t size); +void* operator new(size_t size); -void *operator new(size_t, void *p) throw(); +void* operator new(size_t, void* p) throw(); -void *operator new[](size_t size); +void* operator new[](size_t size); -void *operator new[](size_t, void *p) throw(); +void* operator new[](size_t, void* p) throw(); -void operator delete(void *p); +void operator delete(void* p); -void operator delete(void *p, size_t size); +void operator delete(void* p, size_t size); -void operator delete(void *, void *) throw(); +void operator delete(void*, void*) throw(); -void operator delete[](void *p); +void operator delete[](void* p); -void operator delete[](void *p, size_t size); +void operator delete[](void* p, size_t size); -void operator delete[](void *, void *) throw(); +void operator delete[](void*, void*) throw(); -void *operator new(size_t, std::align_val_t); -void operator delete(void *, std::align_val_t); -void *operator new[](size_t, std::align_val_t); -void operator delete[](void *, std::align_val_t); -void operator delete(void *, size_t, std::align_val_t); -void operator delete[](void *, size_t, std::align_val_t); +void* operator new(size_t, std::align_val_t); +void operator delete(void*, std::align_val_t); +void* operator new[](size_t, std::align_val_t); +void operator delete[](void*, std::align_val_t); +void operator delete(void*, size_t, std::align_val_t); +void operator delete[](void*, size_t, std::align_val_t); -#endif /* _NEW_ */ +#endif /* SIMPLEKERNEL_NEW */ diff --git a/src/libcxx/include/numeric b/src/libcxx/include/numeric index 9ffb6a38b..bf080df99 100644 --- a/src/libcxx/include/numeric +++ b/src/libcxx/include/numeric @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// numeric for Simple-XX/SimpleKernel. +/** + * @file numeric + * @brief stl numeric 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ -#ifndef _NUMERIC_ -#define _NUMERIC_ +#ifndef SIMPLEKERNEL_NUMERIC +#define SIMPLEKERNEL_NUMERIC // 这个头文件包含了 std 的数值算法 @@ -13,137 +24,141 @@ namespace mystl { - /*****************************************************************************************/ - // accumulate - // 版本1:以初值 init 对每个元素进行累加 - // 版本2:以初值 init 对每个元素进行二元操作 - /*****************************************************************************************/ - // 版本1 - template - T accumulate(InputIter first, InputIter last, T init) { - for (; first != last; ++first) { - init += *first; - } - return init; +/*****************************************************************************************/ +// accumulate +// 版本1:以初值 init 对每个元素进行累加 +// 版本2:以初值 init 对每个元素进行二元操作 +/*****************************************************************************************/ +// 版本1 +template +T accumulate(InputIter first, InputIter last, T init) { + for (; first != last; ++first) { + init += *first; } + return init; +} - // 版本2 - template - T accumulate(InputIter first, InputIter last, T init, BinaryOp binary_op) { - for (; first != last; ++first) { - init = binary_op(init, *first); - } - return init; +// 版本2 +template +T accumulate(InputIter first, InputIter last, T init, BinaryOp binary_op) { + for (; first != last; ++first) { + init = binary_op(init, *first); } + return init; +} - /*****************************************************************************************/ - // adjacent_difference - // 版本1:计算相邻元素的差值,结果保存到以 result 为起始的区间上 - // 版本2:自定义相邻元素的二元操作 - /*****************************************************************************************/ - // 版本1 - template - OutputIter adjacent_difference(InputIter first, InputIter last, - OutputIter result) { - if (first == last) - return result; - *result = *first; // 记录第一个元素 - auto value = *first; - while (++first != last) { - auto tmp = *first; - *++result = tmp - value; - value = tmp; - } - return ++result; +/*****************************************************************************************/ +// adjacent_difference +// 版本1:计算相邻元素的差值,结果保存到以 result 为起始的区间上 +// 版本2:自定义相邻元素的二元操作 +/*****************************************************************************************/ +// 版本1 +template +OutputIter +adjacent_difference(InputIter first, InputIter last, OutputIter result) { + if (first == last) { + return result; } + *result = *first; // 记录第一个元素 + auto value = *first; + while (++first != last) { + auto tmp = *first; + *++result = tmp - value; + value = tmp; + } + return ++result; +} - // 版本2 - template - OutputIter adjacent_difference(InputIter first, InputIter last, - OutputIter result, BinaryOp binary_op) { - if (first == last) - return result; - *result = *first; // 记录第一个元素 - auto value = *first; - while (++first != last) { - auto tmp = *first; - *++result = binary_op(tmp, value); - value = tmp; - } - return ++result; +// 版本2 +template +OutputIter adjacent_difference(InputIter first, InputIter last, + OutputIter result, BinaryOp binary_op) { + if (first == last) { + return result; + } + *result = *first; // 记录第一个元素 + auto value = *first; + while (++first != last) { + auto tmp = *first; + *++result = binary_op(tmp, value); + value = tmp; } + return ++result; +} - /*****************************************************************************************/ - // inner_product - // 版本1:以 init 为初值,计算两个区间的内积 - // 版本2:自定义 operator+ 和 operator* - /*****************************************************************************************/ - // 版本1 - template - T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, - T init) { - for (; first1 != last1; ++first1, ++first2) { - init = init + (*first1 * *first2); - } - return init; +/*****************************************************************************************/ +// inner_product +// 版本1:以 init 为初值,计算两个区间的内积 +// 版本2:自定义 operator+ 和 operator* +/*****************************************************************************************/ +// 版本1 +template +T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, + T init) { + for (; first1 != last1; ++first1, ++first2) { + init = init + (*first1 * *first2); } + return init; +} - // 版本2 - template - T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, - T init, BinaryOp1 binary_op1, BinaryOp2 binary_op2) { - for (; first1 != last1; ++first1, ++first2) { - init = binary_op1(init, binary_op2(*first1, *first2)); - } - return init; +// 版本2 +template +T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, T init, + BinaryOp1 binary_op1, BinaryOp2 binary_op2) { + for (; first1 != last1; ++first1, ++first2) { + init = binary_op1(init, binary_op2(*first1, *first2)); } + return init; +} - /*****************************************************************************************/ - // iota - // 填充[first, last),以 value 为初值开始递增 - /*****************************************************************************************/ - template - void iota(ForwardIter first, ForwardIter last, T value) { - while (first != last) { - *first++ = value; - ++value; - } +/*****************************************************************************************/ +// iota +// 填充[first, last),以 value 为初值开始递增 +/*****************************************************************************************/ +template +void iota(ForwardIter first, ForwardIter last, T value) { + while (first != last) { + *first++ = value; + ++value; } +} - /*****************************************************************************************/ - // partial_sum - // 版本1:计算局部累计求和,结果保存到以 result 为起始的区间上 - // 版本2:进行局部进行自定义二元操作 - /*****************************************************************************************/ - template - OutputIter partial_sum(InputIter first, InputIter last, OutputIter result) { - if (first == last) - return result; - *result = *first; // 记录第一个元素 - auto value = *first; - while (++first != last) { - value = value + *first; - *++result = value; - } - return ++result; +/*****************************************************************************************/ +// partial_sum +// 版本1:计算局部累计求和,结果保存到以 result 为起始的区间上 +// 版本2:进行局部进行自定义二元操作 +/*****************************************************************************************/ +template +OutputIter partial_sum(InputIter first, InputIter last, OutputIter result) { + if (first == last) { + return result; } + *result = *first; // 记录第一个元素 + auto value = *first; + while (++first != last) { + value = value + *first; + *++result = value; + } + return ++result; +} - // 版本2 - template - OutputIter partial_sum(InputIter first, InputIter last, OutputIter result, - BinaryOp binary_op) { - if (first == last) - return result; - *result = *first; //记录第一个元素 - auto value = *first; - while (++first != last) { - value = binary_op(value, *first); - *++result = value; - } - return ++result; +// 版本2 +template +OutputIter partial_sum(InputIter first, InputIter last, OutputIter result, + BinaryOp binary_op) { + if (first == last) { + return result; + } + *result = *first; // 记录第一个元素 + auto value = *first; + while (++first != last) { + value = binary_op(value, *first); + *++result = value; } + return ++result; +} -}; +}; // namespace mystl -#endif /* _NUMERIC_ */ +#endif /* SIMPLEKERNEL_NUMERIC */ diff --git a/src/libcxx/include/queue b/src/libcxx/include/queue index a43741ec8..0e22299e2 100644 --- a/src/libcxx/include/queue +++ b/src/libcxx/include/queue @@ -1,353 +1,381 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// queue for Simple-XX/SimpleKernel. - -#ifndef _QUEUE_ -#define _QUEUE_ +/** + * @file queue + * @brief stl queue 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_QUEUE +#define SIMPLEKERNEL_QUEUE // 这个头文件包含了两个模板类 queue 和 priority_queue // queue : 队列 // priority_queue : 优先队列 #include "deque" -#include "vector" #include "functional" #include "heap_algo" +#include "vector" namespace mystl { - // 模板类 queue - // 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque - // 作为底层容器 - template > - class queue { - public: - typedef Container container_type; - // 使用底层容器的型别 - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; +// 模板类 queue +// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque +// 作为底层容器 +template > +class queue { +public: + typedef Container container_type; + // 使用底层容器的型别 + typedef typename Container::value_type value_type; + typedef typename Container::size_type size_type; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; - static_assert(std::is_same::value, - "the value_type of Container should be same with T"); + static_assert(std::is_same::value, + "the value_type of Container should be same with T"); - private: - container_type c_; // 用底层容器表现 queue +private: + container_type c_; // 用底层容器表现 queue - public: - // 构造、复制、移动函数 +public: + // 构造、复制、移动函数 - queue() = default; + queue() = default; - explicit queue(size_type n) : c_(n) { - } - queue(size_type n, const value_type &value) : c_(n, value) { - } + explicit queue(size_type n) : c_(n) { + } - template - queue(IIter first, IIter last) : c_(first, last) { - } + queue(size_type n, const value_type& value) : c_(n, value) { + } - queue(std::initializer_list ilist) : c_(ilist.begin(), ilist.end()) { - } + template + queue(IIter first, IIter last) : c_(first, last) { + } - queue(const Container &c) : c_(c) { - } - queue(Container &&c) noexcept( - std::is_nothrow_move_constructible::value) - : c_(mystl::move(c)) { - } + queue(std::initializer_list ilist) : c_(ilist.begin(), ilist.end()) { + } - queue(const queue &rhs) : c_(rhs.c_) { - } - queue(queue &&rhs) noexcept( - std::is_nothrow_move_constructible::value) - : c_(mystl::move(rhs.c_)) { - } + queue(const Container& c) : c_(c) { + } - queue &operator=(const queue &rhs) { - c_ = rhs.c_; - return *this; - } - queue &operator=(queue &&rhs) noexcept( - std::is_nothrow_move_assignable::value) { - c_ = mystl::move(rhs.c_); - return *this; - } + queue(Container&& c) noexcept( + std::is_nothrow_move_constructible::value) + : c_(mystl::move(c)) { + } - queue &operator=(std::initializer_list ilist) { - c_ = ilist; - return *this; - } + queue(const queue& rhs) : c_(rhs.c_) { + } - ~queue() = default; + queue(queue&& rhs) noexcept( + std::is_nothrow_move_constructible::value) + : c_(mystl::move(rhs.c_)) { + } - // 访问元素相关操作 - reference front() { - return c_.front(); - } - const_reference front() const { - return c_.front(); - } - reference back() { - return c_.back(); - } - const_reference back() const { - return c_.back(); - } + queue& operator=(const queue& rhs) { + c_ = rhs.c_; + return *this; + } - // 容量相关操作 - bool empty() const noexcept { - return c_.empty(); - } - size_type size() const noexcept { - return c_.size(); - } + queue& operator=(queue&& rhs) noexcept( + std::is_nothrow_move_assignable::value) { + c_ = mystl::move(rhs.c_); + return *this; + } - // 修改容器相关操作 - template - void emplace(Args &&...args) { - c_.emplace_back(mystl::forward(args)...); - } + queue& operator=(std::initializer_list ilist) { + c_ = ilist; + return *this; + } - void push(const value_type &value) { - c_.push_back(value); - } - void push(value_type &&value) { - c_.emplace_back(mystl::move(value)); - } + ~queue() = default; - void pop() { - c_.pop_front(); - } + // 访问元素相关操作 + reference front() { + return c_.front(); + } - void clear() { - while (!empty()) - pop(); - } + const_reference front() const { + return c_.front(); + } - void swap(queue &rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) { - mystl::swap(c_, rhs.c_); - } + reference back() { + return c_.back(); + } - public: - friend bool operator==(const queue &lhs, const queue &rhs) { - return lhs.c_ == rhs.c_; - } - friend bool operator<(const queue &lhs, const queue &rhs) { - return lhs.c_ < rhs.c_; - } - }; + const_reference back() const { + return c_.back(); + } + + // 容量相关操作 + bool empty() const noexcept { + return c_.empty(); + } + + size_type size() const noexcept { + return c_.size(); + } - // 重载比较操作符 - template - bool operator==(const queue &lhs, - const queue &rhs) { - return lhs == rhs; + // 修改容器相关操作 + template + void emplace(Args&&... args) { + c_.emplace_back(mystl::forward(args)...); } - template - bool operator!=(const queue &lhs, - const queue &rhs) { - return !(lhs == rhs); + void push(const value_type& value) { + c_.push_back(value); } - template - bool operator<(const queue &lhs, - const queue &rhs) { - return lhs < rhs; + void push(value_type&& value) { + c_.emplace_back(mystl::move(value)); } - template - bool operator>(const queue &lhs, - const queue &rhs) { - return rhs < lhs; + void pop() { + c_.pop_front(); } - template - bool operator<=(const queue &lhs, - const queue &rhs) { - return !(rhs < lhs); + void clear() { + while (!empty()) { + pop(); + } } - template - bool operator>=(const queue &lhs, - const queue &rhs) { - return !(lhs < rhs); + void swap(queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) { + mystl::swap(c_, rhs.c_); } - // 重载 mystl 的 swap - template - void swap(queue &lhs, - queue &rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); +public: + friend bool operator==(const queue& lhs, const queue& rhs) { + return lhs.c_ == rhs.c_; } - /*****************************************************************************************/ + friend bool operator<(const queue& lhs, const queue& rhs) { + return lhs.c_ < rhs.c_; + } +}; - // 模板类 priority_queue - // 参数一代表数据类型,参数二代表容器类型,缺省使用 mystl::vector - // 作为底层容器 参数三代表比较权值的方式,缺省使用 mystl::less 作为比较方式 - template , - class Compare = mystl::less> - class priority_queue { - public: - typedef Container container_type; - typedef Compare value_compare; - // 使用底层容器的型别 - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; +// 重载比较操作符 +template +bool operator==(const queue& lhs, + const queue& rhs) { + return lhs == rhs; +} + +template +bool operator!=(const queue& lhs, + const queue& rhs) { + return !(lhs == rhs); +} + +template +bool operator<(const queue& lhs, const queue& rhs) { + return lhs < rhs; +} + +template +bool operator>(const queue& lhs, const queue& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const queue& lhs, + const queue& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const queue& lhs, + const queue& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(queue& lhs, + queue& rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 priority_queue +// 参数一代表数据类型,参数二代表容器类型,缺省使用 mystl::vector +// 作为底层容器 参数三代表比较权值的方式,缺省使用 mystl::less 作为比较方式 +template , + class Compare = mystl::less> +class priority_queue { +public: + typedef Container container_type; + typedef Compare value_compare; + // 使用底层容器的型别 + typedef typename Container::value_type value_type; + typedef typename Container::size_type size_type; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; + + static_assert(std::is_same::value, + "the value_type of Container should be same with T"); + +private: + container_type c_; // 用底层容器来表现 priority_queue + value_compare comp_; // 权值比较的标准 + +public: + // 构造、复制、移动函数 + priority_queue() = default; + + priority_queue(const Compare& c) : c_(), comp_(c) { + } - static_assert(std::is_same::value, - "the value_type of Container should be same with T"); + explicit priority_queue(size_type n) : c_(n) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - private: - container_type c_; // 用底层容器来表现 priority_queue - value_compare comp_; // 权值比较的标准 + priority_queue(size_type n, const value_type& value) : c_(n, value) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - public: - // 构造、复制、移动函数 - priority_queue() = default; + template + priority_queue(IIter first, IIter last) : c_(first, last) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - priority_queue(const Compare &c) : c_(), comp_(c) { - } + priority_queue(std::initializer_list ilist) : c_(ilist) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - explicit priority_queue(size_type n) : c_(n) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - priority_queue(size_type n, const value_type &value) : c_(n, value) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } + priority_queue(const Container& s) : c_(s) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - template - priority_queue(IIter first, IIter last) : c_(first, last) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } + priority_queue(Container&& s) : c_(mystl::move(s)) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - priority_queue(std::initializer_list ilist) : c_(ilist) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } + priority_queue(const priority_queue& rhs) : c_(rhs.c_), comp_(rhs.comp_) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - priority_queue(const Container &s) : c_(s) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - priority_queue(Container &&s) : c_(mystl::move(s)) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } + priority_queue(priority_queue&& rhs) + : c_(mystl::move(rhs.c_)), comp_(rhs.comp_) { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } - priority_queue(const priority_queue &rhs) - : c_(rhs.c_), comp_(rhs.comp_) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - priority_queue(priority_queue &&rhs) - : c_(mystl::move(rhs.c_)), comp_(rhs.comp_) { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } + priority_queue& operator=(const priority_queue& rhs) { + c_ = rhs.c_; + comp_ = rhs.comp_; + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } - priority_queue &operator=(const priority_queue &rhs) { - c_ = rhs.c_; - comp_ = rhs.comp_; - mystl::make_heap(c_.begin(), c_.end(), comp_); - return *this; - } - priority_queue &operator=(priority_queue &&rhs) { - c_ = mystl::move(rhs.c_); - comp_ = rhs.comp_; - mystl::make_heap(c_.begin(), c_.end(), comp_); - return *this; - } - priority_queue &operator=(std::initializer_list ilist) { - c_ = ilist; - comp_ = value_compare(); - mystl::make_heap(c_.begin(), c_.end(), comp_); - return *this; - } + priority_queue& operator=(priority_queue&& rhs) { + c_ = mystl::move(rhs.c_); + comp_ = rhs.comp_; + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } - ~priority_queue() = default; + priority_queue& operator=(std::initializer_list ilist) { + c_ = ilist; + comp_ = value_compare(); + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } - public: - // 访问元素相关操作 - const_reference top() const { - return c_.front(); - } + ~priority_queue() = default; - // 容量相关操作 - bool empty() const noexcept { - return c_.empty(); - } - size_type size() const noexcept { - return c_.size(); - } +public: + // 访问元素相关操作 + const_reference top() const { + return c_.front(); + } - // 修改容器相关操作 - template - void emplace(Args &&...args) { - c_.emplace_back(mystl::forward(args)...); - mystl::push_heap(c_.begin(), c_.end(), comp_); - } + // 容量相关操作 + bool empty() const noexcept { + return c_.empty(); + } - void push(const value_type &value) { - c_.push_back(value); - mystl::push_heap(c_.begin(), c_.end(), comp_); - } - void push(value_type &&value) { - c_.push_back(mystl::move(value)); - mystl::push_heap(c_.begin(), c_.end(), comp_); - } + size_type size() const noexcept { + return c_.size(); + } - void pop() { - mystl::pop_heap(c_.begin(), c_.end(), comp_); - c_.pop_back(); - } + // 修改容器相关操作 + template + void emplace(Args&&... args) { + c_.emplace_back(mystl::forward(args)...); + mystl::push_heap(c_.begin(), c_.end(), comp_); + } - void clear() { - while (!empty()) - pop(); - } + void push(const value_type& value) { + c_.push_back(value); + mystl::push_heap(c_.begin(), c_.end(), comp_); + } - void swap(priority_queue &rhs) noexcept(noexcept(mystl::swap( - c_, rhs.c_)) &&noexcept(mystl::swap(comp_, rhs.comp_))) { - mystl::swap(c_, rhs.c_); - mystl::swap(comp_, rhs.comp_); - } + void push(value_type&& value) { + c_.push_back(mystl::move(value)); + mystl::push_heap(c_.begin(), c_.end(), comp_); + } - public: - friend bool operator==(const priority_queue &lhs, - const priority_queue &rhs) { - return lhs.c_ == rhs.c_; - } - friend bool operator!=(const priority_queue &lhs, - const priority_queue &rhs) { - return lhs.c_ != rhs.c_; - } - }; + void pop() { + mystl::pop_heap(c_.begin(), c_.end(), comp_); + c_.pop_back(); + } - // 重载比较操作符 - template - bool operator==(priority_queue &lhs, - priority_queue &rhs) { - return lhs == rhs; + void clear() { + while (!empty()) { + pop(); + } } - template - bool operator!=(priority_queue &lhs, - priority_queue &rhs) { - return lhs != rhs; + void swap(priority_queue& rhs) noexcept(noexcept( + mystl::swap(c_, rhs.c_)) && noexcept(mystl::swap(comp_, rhs.comp_))) { + mystl::swap(c_, rhs.c_); + mystl::swap(comp_, rhs.comp_); } - // 重载 mystl 的 swap - template - void swap(priority_queue &lhs, - priority_queue - &rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); +public: + friend bool + operator==(const priority_queue& lhs, const priority_queue& rhs) { + return lhs.c_ == rhs.c_; } + friend bool + operator!=(const priority_queue& lhs, const priority_queue& rhs) { + return lhs.c_ != rhs.c_; + } }; -#endif /* _QUEUE_ */ +// 重载比较操作符 +template +bool operator==(priority_queue& lhs, + priority_queue& rhs) { + return lhs == rhs; +} + +template +bool operator!=(priority_queue& lhs, + priority_queue& rhs) { + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(priority_queue& lhs, + priority_queue& + rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_QUEUE */ diff --git a/src/libcxx/include/rb_tree b/src/libcxx/include/rb_tree index 945a18b48..b60ad283f 100644 --- a/src/libcxx/include/rb_tree +++ b/src/libcxx/include/rb_tree @@ -1,1641 +1,1713 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// rb_tree for Simple-XX/SimpleKernel. - -#ifndef _RB_TREE_ -#define _RB_TREE_ +/** + * @file rb_tree + * @brief stl rb_tree 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_RB_TREE +#define SIMPLEKERNEL_RB_TREE // 这个头文件包含一个模板类 rb_tree // rb_tree : 红黑树 -#include "initializer_list" #include "assert.h" +#include "exceptdef" #include "functional" +#include "initializer_list" #include "iterator" #include "memory" #include "type_traits.h" -#include "exceptdef" namespace mystl { - // rb tree 节点颜色的类型 +// rb tree 节点颜色的类型 - typedef bool rb_tree_color_type; +typedef bool rb_tree_color_type; - static constexpr rb_tree_color_type rb_tree_red = false; - static constexpr rb_tree_color_type rb_tree_black = true; +static constexpr rb_tree_color_type rb_tree_red = false; +static constexpr rb_tree_color_type rb_tree_black = true; - // forward declaration +// forward declaration - template - struct rb_tree_node_base; - template - struct rb_tree_node; +template +struct rb_tree_node_base; +template +struct rb_tree_node; - template - struct rb_tree_iterator; - template - struct rb_tree_const_iterator; +template +struct rb_tree_iterator; +template +struct rb_tree_const_iterator; - // rb tree value traits +// rb tree value traits - template - struct rb_tree_value_traits_imp { - typedef T key_type; - typedef T mapped_type; - typedef T value_type; +template +struct rb_tree_value_traits_imp { + typedef T key_type; + typedef T mapped_type; + typedef T value_type; - template - static const key_type &get_key(const Ty &value) { - return value; - } + template + static const key_type& get_key(const Ty& value) { + return value; + } - template - static const value_type &get_value(const Ty &value) { - return value; - } - }; + template + static const value_type& get_value(const Ty& value) { + return value; + } +}; - template - struct rb_tree_value_traits_imp { - typedef typename std::remove_cv::type key_type; - typedef typename T::second_type mapped_type; - typedef T value_type; +template +struct rb_tree_value_traits_imp { + typedef typename std::remove_cv::type key_type; + typedef typename T::second_type mapped_type; + typedef T value_type; - template - static const key_type &get_key(const Ty &value) { - return value.first; - } + template + static const key_type& get_key(const Ty& value) { + return value.first; + } - template - static const value_type &get_value(const Ty &value) { - return value; - } - }; + template + static const value_type& get_value(const Ty& value) { + return value; + } +}; - template - struct rb_tree_value_traits { - static constexpr bool is_map = mystl::is_pair::value; +template +struct rb_tree_value_traits { + static constexpr bool is_map = mystl::is_pair::value; - typedef rb_tree_value_traits_imp value_traits_type; + typedef rb_tree_value_traits_imp value_traits_type; - typedef typename value_traits_type::key_type key_type; - typedef typename value_traits_type::mapped_type mapped_type; - typedef typename value_traits_type::value_type value_type; + typedef typename value_traits_type::key_type key_type; + typedef typename value_traits_type::mapped_type mapped_type; + typedef typename value_traits_type::value_type value_type; - template - static const key_type &get_key(const Ty &value) { - return value_traits_type::get_key(value); - } + template + static const key_type& get_key(const Ty& value) { + return value_traits_type::get_key(value); + } - template - static const value_type &get_value(const Ty &value) { - return value_traits_type::get_value(value); - } - }; + template + static const value_type& get_value(const Ty& value) { + return value_traits_type::get_value(value); + } +}; - // rb tree node traits +// rb tree node traits - template - struct rb_tree_node_traits { - typedef rb_tree_color_type color_type; +template +struct rb_tree_node_traits { + typedef rb_tree_color_type color_type; - typedef rb_tree_value_traits value_traits; - typedef typename value_traits::key_type key_type; - typedef typename value_traits::mapped_type mapped_type; - typedef typename value_traits::value_type value_type; + typedef rb_tree_value_traits value_traits; + typedef typename value_traits::key_type key_type; + typedef typename value_traits::mapped_type mapped_type; + typedef typename value_traits::value_type value_type; - typedef rb_tree_node_base *base_ptr; - typedef rb_tree_node * node_ptr; - }; + typedef rb_tree_node_base* base_ptr; + typedef rb_tree_node* node_ptr; +}; - // rb tree 的节点设计 +// rb tree 的节点设计 - template - struct rb_tree_node_base { - typedef rb_tree_color_type color_type; - typedef rb_tree_node_base *base_ptr; - typedef rb_tree_node * node_ptr; +template +struct rb_tree_node_base { + typedef rb_tree_color_type color_type; + typedef rb_tree_node_base* base_ptr; + typedef rb_tree_node* node_ptr; - base_ptr parent; // 父节点 - base_ptr left; // 左子节点 - base_ptr right; // 右子节点 - color_type color; // 节点颜色 + base_ptr parent; // 父节点 + base_ptr left; // 左子节点 + base_ptr right; // 右子节点 + color_type color; // 节点颜色 - base_ptr get_base_ptr() { - return &*this; - } + base_ptr get_base_ptr() { + return &*this; + } - node_ptr get_node_ptr() { - return reinterpret_cast(&*this); - } + node_ptr get_node_ptr() { + return reinterpret_cast(&*this); + } - node_ptr &get_node_ref() { - return reinterpret_cast(*this); - } - }; + node_ptr& get_node_ref() { + return reinterpret_cast(*this); + } +}; - template - struct rb_tree_node : public rb_tree_node_base { - typedef rb_tree_node_base *base_ptr; - typedef rb_tree_node * node_ptr; +template +struct rb_tree_node : public rb_tree_node_base { + typedef rb_tree_node_base* base_ptr; + typedef rb_tree_node* node_ptr; - T value; // 节点值 + T value; // 节点值 - base_ptr get_base_ptr() { - return static_cast(&*this); - } + base_ptr get_base_ptr() { + return static_cast(&*this); + } - node_ptr get_node_ptr() { - return &*this; - } - }; + node_ptr get_node_ptr() { + return &*this; + } +}; - // rb tree traits +// rb tree traits - template - struct rb_tree_traits { - typedef rb_tree_value_traits value_traits; +template +struct rb_tree_traits { + typedef rb_tree_value_traits value_traits; - typedef typename value_traits::key_type key_type; - typedef typename value_traits::mapped_type mapped_type; - typedef typename value_traits::value_type value_type; + typedef typename value_traits::key_type key_type; + typedef typename value_traits::mapped_type mapped_type; + typedef typename value_traits::value_type value_type; - typedef value_type * pointer; - typedef value_type & reference; - typedef const value_type *const_pointer; - typedef const value_type &const_reference; + typedef value_type* pointer; + typedef value_type& reference; + typedef const value_type* const_pointer; + typedef const value_type& const_reference; - typedef rb_tree_node_base base_type; - typedef rb_tree_node node_type; + typedef rb_tree_node_base base_type; + typedef rb_tree_node node_type; - typedef base_type *base_ptr; - typedef node_type *node_ptr; - }; + typedef base_type* base_ptr; + typedef node_type* node_ptr; +}; - // rb tree 的迭代器设计 +// rb tree 的迭代器设计 - template - struct rb_tree_iterator_base - : public mystl::iterator { - typedef typename rb_tree_traits::base_ptr base_ptr; +template +struct rb_tree_iterator_base + : public mystl::iterator { + typedef typename rb_tree_traits::base_ptr base_ptr; - base_ptr node; // 指向节点本身 + base_ptr node; // 指向节点本身 - rb_tree_iterator_base() : node(nullptr) { - } + rb_tree_iterator_base() : node(nullptr) { + } - // 使迭代器前进 - void inc() { - if (node->right != nullptr) { - node = rb_tree_min(node->right); - } - else { // 如果没有右子节点 - auto y = node->parent; - while (y->right == node) { - node = y; - y = y->parent; - } - if (node->right != - y) // 应对“寻找根节点的下一节点,而根节点没有右子节点”的特殊情况 - node = y; - } + // 使迭代器前进 + void inc() { + if (node->right != nullptr) { + node = rb_tree_min(node->right); } - - // 使迭代器后退 - void dec() { - if (node->parent->parent == node && - rb_tree_is_red(node)) { // 如果 node 为 header - node = node->right; // 指向整棵树的 max 节点 - } - else if (node->left != nullptr) { - node = rb_tree_max(node->left); + else { // 如果没有右子节点 + auto y = node->parent; + while (y->right == node) { + node = y; + y = y->parent; } - else { // 非 header 节点,也无左子节点 - auto y = node->parent; - while (node == y->left) { - node = y; - y = y->parent; - } + if ( + node->right + != y) { // 应对“寻找根节点的下一节点,而根节点没有右子节点”的特殊情况 node = y; } } + } - bool operator==(const rb_tree_iterator_base &rhs) { - return node == rhs.node; + // 使迭代器后退 + void dec() { + if (node->parent->parent == node + && rb_tree_is_red(node)) { // 如果 node 为 header + node = node->right; // 指向整棵树的 max 节点 } - bool operator!=(const rb_tree_iterator_base &rhs) { - return node != rhs.node; + else if (node->left != nullptr) { + node = rb_tree_max(node->left); } - }; + else { // 非 header 节点,也无左子节点 + auto y = node->parent; + while (node == y->left) { + node = y; + y = y->parent; + } + node = y; + } + } - template - struct rb_tree_iterator : public rb_tree_iterator_base { - typedef rb_tree_traits tree_traits; + bool operator==(const rb_tree_iterator_base& rhs) { + return node == rhs.node; + } - typedef typename tree_traits::value_type value_type; - typedef typename tree_traits::pointer pointer; - typedef typename tree_traits::reference reference; - typedef typename tree_traits::base_ptr base_ptr; - typedef typename tree_traits::node_ptr node_ptr; + bool operator!=(const rb_tree_iterator_base& rhs) { + return node != rhs.node; + } +}; - typedef rb_tree_iterator iterator; - typedef rb_tree_const_iterator const_iterator; - typedef iterator self; +template +struct rb_tree_iterator : public rb_tree_iterator_base { + typedef rb_tree_traits tree_traits; - using rb_tree_iterator_base::node; + typedef typename tree_traits::value_type value_type; + typedef typename tree_traits::pointer pointer; + typedef typename tree_traits::reference reference; + typedef typename tree_traits::base_ptr base_ptr; + typedef typename tree_traits::node_ptr node_ptr; - // 构造函数 - rb_tree_iterator() { - } - rb_tree_iterator(base_ptr x) { - node = x; - } - rb_tree_iterator(node_ptr x) { - node = x; - } - rb_tree_iterator(const iterator &rhs) { - node = rhs.node; - } - rb_tree_iterator(const const_iterator &rhs) { - node = rhs.node; - } + typedef rb_tree_iterator iterator; + typedef rb_tree_const_iterator const_iterator; + typedef iterator self; - // 重载操作符 - reference operator*() const { - return node->get_node_ptr()->value; - } - pointer operator->() const { - return &(operator*()); - } + using rb_tree_iterator_base::node; - self &operator++() { - this->inc(); - return *this; - } - self operator++(int) { - self tmp(*this); - this->inc(); - return tmp; - } - self &operator--() { - this->dec(); - return *this; - } - self operator--(int) { - self tmp(*this); - this->dec(); - return tmp; - } - }; + // 构造函数 + rb_tree_iterator() { + } - template - struct rb_tree_const_iterator : public rb_tree_iterator_base { - typedef rb_tree_traits tree_traits; + rb_tree_iterator(base_ptr x) { + node = x; + } - typedef typename tree_traits::value_type value_type; - typedef typename tree_traits::const_pointer pointer; - typedef typename tree_traits::const_reference reference; - typedef typename tree_traits::base_ptr base_ptr; - typedef typename tree_traits::node_ptr node_ptr; + rb_tree_iterator(node_ptr x) { + node = x; + } - typedef rb_tree_iterator iterator; - typedef rb_tree_const_iterator const_iterator; - typedef const_iterator self; + rb_tree_iterator(const iterator& rhs) { + node = rhs.node; + } - using rb_tree_iterator_base::node; + rb_tree_iterator(const const_iterator& rhs) { + node = rhs.node; + } - // 构造函数 - rb_tree_const_iterator() { - } - rb_tree_const_iterator(base_ptr x) { - node = x; - } - rb_tree_const_iterator(node_ptr x) { - node = x; - } - rb_tree_const_iterator(const iterator &rhs) { - node = rhs.node; - } - rb_tree_const_iterator(const const_iterator &rhs) { - node = rhs.node; - } + // 重载操作符 + reference operator*() const { + return node->get_node_ptr()->value; + } - // 重载操作符 - reference operator*() const { - return node->get_node_ptr()->value; - } - pointer operator->() const { - return &(operator*()); - } + pointer operator->() const { + return &(operator*()); + } - self &operator++() { - this->inc(); - return *this; - } - self operator++(int) { - self tmp(*this); - this->inc(); - return tmp; - } - self &operator--() { - this->dec(); - return *this; - } - self operator--(int) { - self tmp(*this); - this->dec(); - return tmp; - } - }; + self& operator++() { + this->inc(); + return *this; + } - // tree algorithm + self operator++(int) { + self tmp(*this); + this->inc(); + return tmp; + } - template - NodePtr rb_tree_min(NodePtr x) noexcept { - while (x->left != nullptr) - x = x->left; - return x; + self& operator--() { + this->dec(); + return *this; } - template - NodePtr rb_tree_max(NodePtr x) noexcept { - while (x->right != nullptr) - x = x->right; - return x; + self operator--(int) { + self tmp(*this); + this->dec(); + return tmp; + } +}; + +template +struct rb_tree_const_iterator : public rb_tree_iterator_base { + typedef rb_tree_traits tree_traits; + + typedef typename tree_traits::value_type value_type; + typedef typename tree_traits::const_pointer pointer; + typedef typename tree_traits::const_reference reference; + typedef typename tree_traits::base_ptr base_ptr; + typedef typename tree_traits::node_ptr node_ptr; + + typedef rb_tree_iterator iterator; + typedef rb_tree_const_iterator const_iterator; + typedef const_iterator self; + + using rb_tree_iterator_base::node; + + // 构造函数 + rb_tree_const_iterator() { } - template - bool rb_tree_is_lchild(NodePtr node) noexcept { - return node == node->parent->left; + rb_tree_const_iterator(base_ptr x) { + node = x; } - template - bool rb_tree_is_red(NodePtr node) noexcept { - return node->color == rb_tree_red; + rb_tree_const_iterator(node_ptr x) { + node = x; } - template - void rb_tree_set_black(NodePtr &node) noexcept { - node->color = rb_tree_black; + rb_tree_const_iterator(const iterator& rhs) { + node = rhs.node; } - template - void rb_tree_set_red(NodePtr &node) noexcept { - node->color = rb_tree_red; + rb_tree_const_iterator(const const_iterator& rhs) { + node = rhs.node; } - template - NodePtr rb_tree_next(NodePtr node) noexcept { - if (node->right != nullptr) - return rb_tree_min(node->right); - while (!rb_tree_is_lchild(node)) - node = node->parent; - return node->parent; + // 重载操作符 + reference operator*() const { + return node->get_node_ptr()->value; } - /*---------------------------------------*\ - | p p | - | / \ / \ | - | x d rotate left y d | - | / \ ===========> / \ | - | a y x c | - | / \ / \ | - | b c a b | - \*---------------------------------------*/ - // 左旋,参数一为左旋点,参数二为根节点 - template - void rb_tree_rotate_left(NodePtr x, NodePtr &root) noexcept { - auto y = x->right; // y 为 x 的右子节点 - x->right = y->left; - if (y->left != nullptr) - y->left->parent = x; - y->parent = x->parent; + pointer operator->() const { + return &(operator*()); + } - if (x == root) { // 如果 x 为根节点,让 y 顶替 x 成为根节点 - root = y; + self& operator++() { + this->inc(); + return *this; + } + + self operator++(int) { + self tmp(*this); + this->inc(); + return tmp; + } + + self& operator--() { + this->dec(); + return *this; + } + + self operator--(int) { + self tmp(*this); + this->dec(); + return tmp; + } +}; + +// tree algorithm + +template +NodePtr rb_tree_min(NodePtr x) noexcept { + while (x->left != nullptr) { + x = x->left; + } + return x; +} + +template +NodePtr rb_tree_max(NodePtr x) noexcept { + while (x->right != nullptr) { + x = x->right; + } + return x; +} + +template +bool rb_tree_is_lchild(NodePtr node) noexcept { + return node == node->parent->left; +} + +template +bool rb_tree_is_red(NodePtr node) noexcept { + return node->color == rb_tree_red; +} + +template +void rb_tree_set_black(NodePtr& node) noexcept { + node->color = rb_tree_black; +} + +template +void rb_tree_set_red(NodePtr& node) noexcept { + node->color = rb_tree_red; +} + +template +NodePtr rb_tree_next(NodePtr node) noexcept { + if (node->right != nullptr) { + return rb_tree_min(node->right); + } + while (!rb_tree_is_lchild(node)) { + node = node->parent; + } + return node->parent; +} + +/*---------------------------------------*\ +| p p | +| / \ / \ | +| x d rotate left y d | +| / \ ===========> / \ | +| a y x c | +| / \ / \ | +| b c a b | +\*---------------------------------------*/ +// 左旋,参数一为左旋点,参数二为根节点 +template +void rb_tree_rotate_left(NodePtr x, NodePtr& root) noexcept { + auto y = x->right; // y 为 x 的右子节点 + x->right = y->left; + if (y->left != nullptr) { + y->left->parent = x; + } + y->parent = x->parent; + + if (x == root) { // 如果 x 为根节点,让 y 顶替 x 成为根节点 + root = y; + } + else if (rb_tree_is_lchild(x)) { // 如果 x 是左子节点 + x->parent->left = y; + } + else { // 如果 x 是右子节点 + x->parent->right = y; + } + // 调整 x 与 y 的关系 + y->left = x; + x->parent = y; +} + +/*----------------------------------------*\ +| p p | +| / \ / \ | +| d x rotate right d y | +| / \ ===========> / \ | +| y a b x | +| / \ / \ | +| b c c a | +\*----------------------------------------*/ +// 右旋,参数一为右旋点,参数二为根节点 +template +void rb_tree_rotate_right(NodePtr x, NodePtr& root) noexcept { + auto y = x->left; + x->left = y->right; + if (y->right) { + y->right->parent = x; + } + y->parent = x->parent; + + if (x == root) { // 如果 x 为根节点,让 y 顶替 x 成为根节点 + root = y; + } + else if (rb_tree_is_lchild(x)) { // 如果 x 是右子节点 + x->parent->left = y; + } + else { // 如果 x 是左子节点 + x->parent->right = y; + } + // 调整 x 与 y 的关系 + y->right = x; + x->parent = y; +} + +// 插入节点后使 rb tree 重新平衡,参数一为新增节点,参数二为根节点 +// +// case 1: 新增节点位于根节点,令新增节点为黑 +// case 2: 新增节点的父节点为黑,没有破坏平衡,直接返回 +// case 3: 父节点和叔叔节点都为红,令父节点和叔叔节点为黑,祖父节点为红, +// 然后令祖父节点为当前节点,继续处理 +// case 4: 父节点为红,叔叔节点为 NIL +// 或黑色,父节点为左(右)孩子,当前节点为右(左)孩子, +// 让父节点成为当前节点,再以当前节点为支点左(右)旋 +// case 5: 父节点为红,叔叔节点为 NIL +// 或黑色,父节点为左(右)孩子,当前节点为左(右)孩子, +// 让父节点变为黑色,祖父节点变为红色,以祖父节点为支点右(左)旋 +// +// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630 +// http://blog.csdn.net/v_JULY_v/article/details/6109153 +template +void rb_tree_insert_rebalance(NodePtr x, NodePtr& root) noexcept { + rb_tree_set_red(x); // 新增节点为红色 + while (x != root && rb_tree_is_red(x->parent)) { + if (rb_tree_is_lchild(x->parent)) { // 如果父节点是左子节点 + auto uncle = x->parent->parent->right; + if (uncle != nullptr + && rb_tree_is_red(uncle)) { // case 3: 父节点和叔叔节点都为红 + rb_tree_set_black(x->parent); + rb_tree_set_black(uncle); + x = x->parent->parent; + rb_tree_set_red(x); + } + else { // 无叔叔节点或叔叔节点为黑 + if (!rb_tree_is_lchild(x)) { // case 4: 当前节点 x 为右子节点 + x = x->parent; + rb_tree_rotate_left(x, root); + } + // 都转换成 case 5: 当前节点为左子节点 + rb_tree_set_black(x->parent); + rb_tree_set_red(x->parent->parent); + rb_tree_rotate_right(x->parent->parent, root); + break; + } } - else if (rb_tree_is_lchild(x)) { // 如果 x 是左子节点 - x->parent->left = y; + else // 如果父节点是右子节点,对称处理 + { + auto uncle = x->parent->parent->left; + if (uncle != nullptr + && rb_tree_is_red(uncle)) { // case 3: 父节点和叔叔节点都为红 + rb_tree_set_black(x->parent); + rb_tree_set_black(uncle); + x = x->parent->parent; + rb_tree_set_red(x); + // 此时祖父节点为红,可能会破坏红黑树的性质,令当前节点为祖父节点,继续处理 + } + else { // 无叔叔节点或叔叔节点为黑 + if (rb_tree_is_lchild(x)) { // case 4: 当前节点 x 为左子节点 + x = x->parent; + rb_tree_rotate_right(x, root); + } + // 都转换成 case 5: 当前节点为左子节点 + rb_tree_set_black(x->parent); + rb_tree_set_red(x->parent->parent); + rb_tree_rotate_left(x->parent->parent, root); + break; + } } - else { // 如果 x 是右子节点 - x->parent->right = y; + } + rb_tree_set_black(root); // 根节点永远为黑 +} + +// 删除节点后使 rb tree +// 重新平衡,参数一为要删除的节点,参数二为根节点,参数三为最小节点,参数四为最大节点 +// +// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630 +// http://blog.csdn.net/v_JULY_v/article/details/6109153 +template +NodePtr rb_tree_erase_rebalance(NodePtr z, NodePtr& root, NodePtr& leftmost, + NodePtr& rightmost) { + // y 是可能的替换节点,指向最终要删除的节点 + auto y = (z->left == nullptr || z->right == nullptr) ? z : rb_tree_next(z); + // x 是 y 的一个独子节点或 NIL 节点 + auto x = y->left != nullptr ? y->left : y->right; + // xp 为 x 的父节点 + NodePtr xp = nullptr; + + // y != z 说明 z 有两个非空子节点,此时 y 指向 z 右子树的最左节点,x + // 指向 y 的右子节点。 用 y 顶替 z 的位置,用 x 顶替 y 的位置,最后用 y + // 指向 z + if (y != z) { + z->left->parent = y; + y->left = z->left; + + // 如果 y 不是 z 的右子节点,那么 z 的右子节点一定有左孩子 + if (y != z->right) { // x 替换 y 的位置 + xp = y->parent; + if (x != nullptr) { + x->parent = y->parent; + } + + y->parent->left = x; + y->right = z->right; + z->right->parent = y; } - // 调整 x 与 y 的关系 - y->left = x; - x->parent = y; - } - - /*----------------------------------------*\ - | p p | - | / \ / \ | - | d x rotate right d y | - | / \ ===========> / \ | - | y a b x | - | / \ / \ | - | b c c a | - \*----------------------------------------*/ - // 右旋,参数一为右旋点,参数二为根节点 - template - void rb_tree_rotate_right(NodePtr x, NodePtr &root) noexcept { - auto y = x->left; - x->left = y->right; - if (y->right) - y->right->parent = x; - y->parent = x->parent; - - if (x == root) { // 如果 x 为根节点,让 y 顶替 x 成为根节点 + else { + xp = y; + } + + // 连接 y 与 z 的父节点 + if (root == z) { root = y; } - else if (rb_tree_is_lchild(x)) { // 如果 x 是右子节点 - x->parent->left = y; + else if (rb_tree_is_lchild(z)) { + z->parent->left = y; } - else { // 如果 x 是左子节点 - x->parent->right = y; + else { + z->parent->right = y; } - // 调整 x 与 y 的关系 - y->right = x; - x->parent = y; - } - - // 插入节点后使 rb tree 重新平衡,参数一为新增节点,参数二为根节点 - // - // case 1: 新增节点位于根节点,令新增节点为黑 - // case 2: 新增节点的父节点为黑,没有破坏平衡,直接返回 - // case 3: 父节点和叔叔节点都为红,令父节点和叔叔节点为黑,祖父节点为红, - // 然后令祖父节点为当前节点,继续处理 - // case 4: 父节点为红,叔叔节点为 NIL - // 或黑色,父节点为左(右)孩子,当前节点为右(左)孩子, - // 让父节点成为当前节点,再以当前节点为支点左(右)旋 - // case 5: 父节点为红,叔叔节点为 NIL - // 或黑色,父节点为左(右)孩子,当前节点为左(右)孩子, - // 让父节点变为黑色,祖父节点变为红色,以祖父节点为支点右(左)旋 - // - // 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630 - // http://blog.csdn.net/v_JULY_v/article/details/6109153 - template - void rb_tree_insert_rebalance(NodePtr x, NodePtr &root) noexcept { - rb_tree_set_red(x); // 新增节点为红色 - while (x != root && rb_tree_is_red(x->parent)) { - if (rb_tree_is_lchild(x->parent)) { // 如果父节点是左子节点 - auto uncle = x->parent->parent->right; - if (uncle != nullptr && - rb_tree_is_red(uncle)) { // case 3: 父节点和叔叔节点都为红 - rb_tree_set_black(x->parent); - rb_tree_set_black(uncle); - x = x->parent->parent; - rb_tree_set_red(x); - } - else { // 无叔叔节点或叔叔节点为黑 - if (!rb_tree_is_lchild( - x)) { // case 4: 当前节点 x 为右子节点 - x = x->parent; - rb_tree_rotate_left(x, root); - } - // 都转换成 case 5: 当前节点为左子节点 - rb_tree_set_black(x->parent); - rb_tree_set_red(x->parent->parent); - rb_tree_rotate_right(x->parent->parent, root); - break; - } - } - else // 如果父节点是右子节点,对称处理 - { - auto uncle = x->parent->parent->left; - if (uncle != nullptr && - rb_tree_is_red(uncle)) { // case 3: 父节点和叔叔节点都为红 - rb_tree_set_black(x->parent); - rb_tree_set_black(uncle); - x = x->parent->parent; - rb_tree_set_red(x); - // 此时祖父节点为红,可能会破坏红黑树的性质,令当前节点为祖父节点,继续处理 - } - else { // 无叔叔节点或叔叔节点为黑 - if (rb_tree_is_lchild(x)) { // case 4: 当前节点 x 为左子节点 - x = x->parent; - rb_tree_rotate_right(x, root); - } - // 都转换成 case 5: 当前节点为左子节点 - rb_tree_set_black(x->parent); - rb_tree_set_red(x->parent->parent); - rb_tree_rotate_left(x->parent->parent, root); - break; - } - } + y->parent = z->parent; + mystl::swap(y->color, z->color); + y = z; + } + // y == z 说明 z 至多只有一个孩子 + else { + xp = y->parent; + if (x) { + x->parent = y->parent; } - rb_tree_set_black(root); // 根节点永远为黑 - } - - // 删除节点后使 rb tree - // 重新平衡,参数一为要删除的节点,参数二为根节点,参数三为最小节点,参数四为最大节点 - // - // 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630 - // http://blog.csdn.net/v_JULY_v/article/details/6109153 - template - NodePtr rb_tree_erase_rebalance(NodePtr z, NodePtr &root, NodePtr &leftmost, - NodePtr &rightmost) { - // y 是可能的替换节点,指向最终要删除的节点 - auto y = - (z->left == nullptr || z->right == nullptr) ? z : rb_tree_next(z); - // x 是 y 的一个独子节点或 NIL 节点 - auto x = y->left != nullptr ? y->left : y->right; - // xp 为 x 的父节点 - NodePtr xp = nullptr; - - // y != z 说明 z 有两个非空子节点,此时 y 指向 z 右子树的最左节点,x - // 指向 y 的右子节点。 用 y 顶替 z 的位置,用 x 顶替 y 的位置,最后用 y - // 指向 z - if (y != z) { - z->left->parent = y; - y->left = z->left; - - // 如果 y 不是 z 的右子节点,那么 z 的右子节点一定有左孩子 - if (y != z->right) { // x 替换 y 的位置 - xp = y->parent; - if (x != nullptr) - x->parent = y->parent; - - y->parent->left = x; - y->right = z->right; - z->right->parent = y; - } - else { - xp = y; - } - // 连接 y 与 z 的父节点 - if (root == z) - root = y; - else if (rb_tree_is_lchild(z)) - z->parent->left = y; - else - z->parent->right = y; - y->parent = z->parent; - mystl::swap(y->color, z->color); - y = z; + // 连接 x 与 z 的父节点 + if (root == z) { + root = x; + } + else if (rb_tree_is_lchild(z)) { + z->parent->left = x; } - // y == z 说明 z 至多只有一个孩子 else { - xp = y->parent; - if (x) - x->parent = y->parent; + z->parent->right = x; + } - // 连接 x 与 z 的父节点 - if (root == z) - root = x; - else if (rb_tree_is_lchild(z)) - z->parent->left = x; - else - z->parent->right = x; - - // 此时 z 有可能是最左节点或最右节点,更新数据 - if (leftmost == z) - leftmost = x == nullptr ? xp : rb_tree_min(x); - if (rightmost == z) - rightmost = x == nullptr ? xp : rb_tree_max(x); + // 此时 z 有可能是最左节点或最右节点,更新数据 + if (leftmost == z) { + leftmost = x == nullptr ? xp : rb_tree_min(x); + } + if (rightmost == z) { + rightmost = x == nullptr ? xp : rb_tree_max(x); } + } - // 此时,y 指向要删除的节点,x 为替代节点,从 x 节点开始调整。 - // 如果删除的节点为红色,树的性质没有被破坏,否则按照以下情况调整(x - // 为左子节点为例): case 1: - // 兄弟节点为红色,令父节点为红,兄弟节点为黑,进行左(右)旋,继续处理 - // case 2: 兄弟节点为黑色,且两个子节点都为黑色或 - // NIL,令兄弟节点为红,父节点成为当前节点,继续处理 case 3: - // 兄弟节点为黑色,左子节点为红色或 NIL,右子节点为黑色或 NIL, - // 令兄弟节点为红,兄弟节点的左子节点为黑,以兄弟节点为支点右(左)旋,继续处理 - // case 4: - // 兄弟节点为黑色,右子节点为红色,令兄弟节点为父节点的颜色,父节点为黑色,兄弟节点的右子节点 - // 为黑色,以父节点为支点左(右)旋,树的性质调整完成,算法结束 - if (!rb_tree_is_red(y)) { // x 为黑色时,调整,否则直接将 x 变为黑色即可 - while (x != root && (x == nullptr || !rb_tree_is_red(x))) { - if (x == xp->left) { // 如果 x 为左子节点 - auto brother = xp->right; - if (rb_tree_is_red(brother)) { // case 1 - rb_tree_set_black(brother); - rb_tree_set_red(xp); - rb_tree_rotate_left(xp, root); - brother = xp->right; - } - // case 1 转为为了 case 2、3、4 中的一种 - if ((brother->left == nullptr || - !rb_tree_is_red(brother->left)) && - (brother->right == nullptr || - !rb_tree_is_red(brother->right))) { // case 2 + // 此时,y 指向要删除的节点,x 为替代节点,从 x 节点开始调整。 + // 如果删除的节点为红色,树的性质没有被破坏,否则按照以下情况调整(x + // 为左子节点为例): case 1: + // 兄弟节点为红色,令父节点为红,兄弟节点为黑,进行左(右)旋,继续处理 + // case 2: 兄弟节点为黑色,且两个子节点都为黑色或 + // NIL,令兄弟节点为红,父节点成为当前节点,继续处理 case 3: + // 兄弟节点为黑色,左子节点为红色或 NIL,右子节点为黑色或 NIL, + // 令兄弟节点为红,兄弟节点的左子节点为黑,以兄弟节点为支点右(左)旋,继续处理 + // case 4: + // 兄弟节点为黑色,右子节点为红色,令兄弟节点为父节点的颜色,父节点为黑色,兄弟节点的右子节点 + // 为黑色,以父节点为支点左(右)旋,树的性质调整完成,算法结束 + if (!rb_tree_is_red(y)) { // x 为黑色时,调整,否则直接将 x 变为黑色即可 + while (x != root && (x == nullptr || !rb_tree_is_red(x))) { + if (x == xp->left) { // 如果 x 为左子节点 + auto brother = xp->right; + if (rb_tree_is_red(brother)) { // case 1 + rb_tree_set_black(brother); + rb_tree_set_red(xp); + rb_tree_rotate_left(xp, root); + brother = xp->right; + } + // case 1 转为为了 case 2、3、4 中的一种 + if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) + && (brother->right == nullptr + || !rb_tree_is_red(brother->right))) { // case 2 + rb_tree_set_red(brother); + x = xp; + xp = xp->parent; + } + else { + if (brother->right == nullptr + || !rb_tree_is_red(brother->right)) { // case 3 + if (brother->left != nullptr) { + rb_tree_set_black(brother->left); + } rb_tree_set_red(brother); - x = xp; - xp = xp->parent; + rb_tree_rotate_right(brother, root); + brother = xp->right; } - else { - if (brother->right == nullptr || - !rb_tree_is_red(brother->right)) { // case 3 - if (brother->left != nullptr) - rb_tree_set_black(brother->left); - rb_tree_set_red(brother); - rb_tree_rotate_right(brother, root); - brother = xp->right; - } - // 转为 case 4 - brother->color = xp->color; - rb_tree_set_black(xp); - if (brother->right != nullptr) - rb_tree_set_black(brother->right); - rb_tree_rotate_left(xp, root); - break; + // 转为 case 4 + brother->color = xp->color; + rb_tree_set_black(xp); + if (brother->right != nullptr) { + rb_tree_set_black(brother->right); } + rb_tree_rotate_left(xp, root); + break; } - else // x 为右子节点,对称处理 - { - auto brother = xp->left; - if (rb_tree_is_red(brother)) { // case 1 - rb_tree_set_black(brother); - rb_tree_set_red(xp); - rb_tree_rotate_right(xp, root); - brother = xp->left; - } - if ((brother->left == nullptr || - !rb_tree_is_red(brother->left)) && - (brother->right == nullptr || - !rb_tree_is_red(brother->right))) { // case 2 + } + else // x 为右子节点,对称处理 + { + auto brother = xp->left; + if (rb_tree_is_red(brother)) { // case 1 + rb_tree_set_black(brother); + rb_tree_set_red(xp); + rb_tree_rotate_right(xp, root); + brother = xp->left; + } + if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) + && (brother->right == nullptr + || !rb_tree_is_red(brother->right))) { // case 2 + rb_tree_set_red(brother); + x = xp; + xp = xp->parent; + } + else { + if (brother->left == nullptr + || !rb_tree_is_red(brother->left)) { // case 3 + if (brother->right != nullptr) { + rb_tree_set_black(brother->right); + } rb_tree_set_red(brother); - x = xp; - xp = xp->parent; + rb_tree_rotate_left(brother, root); + brother = xp->left; } - else { - if (brother->left == nullptr || - !rb_tree_is_red(brother->left)) { // case 3 - if (brother->right != nullptr) - rb_tree_set_black(brother->right); - rb_tree_set_red(brother); - rb_tree_rotate_left(brother, root); - brother = xp->left; - } - // 转为 case 4 - brother->color = xp->color; - rb_tree_set_black(xp); - if (brother->left != nullptr) - rb_tree_set_black(brother->left); - rb_tree_rotate_right(xp, root); - break; + // 转为 case 4 + brother->color = xp->color; + rb_tree_set_black(xp); + if (brother->left != nullptr) { + rb_tree_set_black(brother->left); } + rb_tree_rotate_right(xp, root); + break; } } - if (x != nullptr) - rb_tree_set_black(x); - } - return y; - } - - // 模板类 rb_tree - // 参数一代表数据类型,参数二代表键值比较类型 - template - class rb_tree { - public: - // rb_tree 的嵌套型别定义 - - typedef rb_tree_traits tree_traits; - typedef rb_tree_value_traits value_traits; - - typedef typename tree_traits::base_type base_type; - typedef typename tree_traits::base_ptr base_ptr; - typedef typename tree_traits::node_type node_type; - typedef typename tree_traits::node_ptr node_ptr; - typedef typename tree_traits::key_type key_type; - typedef typename tree_traits::mapped_type mapped_type; - typedef typename tree_traits::value_type value_type; - typedef Compare key_compare; - - typedef mystl::allocator allocator_type; - typedef mystl::allocator data_allocator; - typedef mystl::allocator base_allocator; - typedef mystl::allocator node_allocator; - - typedef typename allocator_type::pointer pointer; - typedef typename allocator_type::const_pointer const_pointer; - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - typedef typename allocator_type::size_type size_type; - typedef typename allocator_type::difference_type difference_type; - - typedef rb_tree_iterator iterator; - typedef rb_tree_const_iterator const_iterator; - typedef mystl::reverse_iterator reverse_iterator; - typedef mystl::reverse_iterator const_reverse_iterator; - - allocator_type get_allocator() const { - return node_allocator(); } - key_compare key_comp() const { - return key_comp_; + if (x != nullptr) { + rb_tree_set_black(x); } + } + return y; +} + +// 模板类 rb_tree +// 参数一代表数据类型,参数二代表键值比较类型 +template +class rb_tree { +public: + // rb_tree 的嵌套型别定义 + + typedef rb_tree_traits tree_traits; + typedef rb_tree_value_traits value_traits; + + typedef typename tree_traits::base_type base_type; + typedef typename tree_traits::base_ptr base_ptr; + typedef typename tree_traits::node_type node_type; + typedef typename tree_traits::node_ptr node_ptr; + typedef typename tree_traits::key_type key_type; + typedef typename tree_traits::mapped_type mapped_type; + typedef typename tree_traits::value_type value_type; + typedef Compare key_compare; + + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator base_allocator; + typedef mystl::allocator node_allocator; + + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef rb_tree_iterator iterator; + typedef rb_tree_const_iterator const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + allocator_type get_allocator() const { + return node_allocator(); + } - private: - // 用以下三个数据表现 rb tree - base_ptr header_; // 特殊节点,与根节点互为对方的父节点 - size_type node_count_; // 节点数 - key_compare key_comp_; // 节点键值比较的准则 + key_compare key_comp() const { + return key_comp_; + } - private: - // 以下三个函数用于取得根节点,最小节点和最大节点 - base_ptr &root() const { - return header_->parent; - } - base_ptr &leftmost() const { - return header_->left; - } - base_ptr &rightmost() const { - return header_->right; - } +private: + // 用以下三个数据表现 rb tree + base_ptr header_; // 特殊节点,与根节点互为对方的父节点 + size_type node_count_; // 节点数 + key_compare key_comp_; // 节点键值比较的准则 - public: - // 构造、复制、析构函数 - rb_tree() { - rb_tree_init(); - } +private: + // 以下三个函数用于取得根节点,最小节点和最大节点 + base_ptr& root() const { + return header_->parent; + } - rb_tree(const rb_tree &rhs); - rb_tree(rb_tree &&rhs) noexcept; + base_ptr& leftmost() const { + return header_->left; + } - rb_tree &operator=(const rb_tree &rhs); - rb_tree &operator=(rb_tree &&rhs); + base_ptr& rightmost() const { + return header_->right; + } - ~rb_tree() { - clear(); - } +public: + // 构造、复制、析构函数 + rb_tree() { + rb_tree_init(); + } - public: - // 迭代器相关操作 + rb_tree(const rb_tree& rhs); + rb_tree(rb_tree&& rhs) noexcept; - iterator begin() noexcept { - return leftmost(); - } - const_iterator begin() const noexcept { - return leftmost(); - } - iterator end() noexcept { - return header_; - } - const_iterator end() const noexcept { - return header_; - } + rb_tree& operator=(const rb_tree& rhs); + rb_tree& operator=(rb_tree&& rhs); - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } + ~rb_tree() { + clear(); + } - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } +public: + // 迭代器相关操作 - // 容量相关操作 + iterator begin() noexcept { + return leftmost(); + } - bool empty() const noexcept { - return node_count_ == 0; - } - size_type size() const noexcept { - return node_count_; - } - size_type max_size() const noexcept { - return static_cast(-1); - } + const_iterator begin() const noexcept { + return leftmost(); + } - // 插入删除相关操作 + iterator end() noexcept { + return header_; + } - // emplace + const_iterator end() const noexcept { + return header_; + } - template - iterator emplace_multi(Args &&...args); + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } - template - mystl::pair emplace_unique(Args &&...args); + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } - template - iterator emplace_multi_use_hint(iterator hint, Args &&...args); + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - template - iterator emplace_unique_use_hint(iterator hint, Args &&...args); + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - // insert + const_iterator cbegin() const noexcept { + return begin(); + } - iterator insert_multi(const value_type &value); - iterator insert_multi(value_type &&value) { - return emplace_multi(mystl::move(value)); - } + const_iterator cend() const noexcept { + return end(); + } - iterator insert_multi(iterator hint, const value_type &value) { - return emplace_multi_use_hint(hint, value); - } - iterator insert_multi(iterator hint, value_type &&value) { - return emplace_multi_use_hint(hint, mystl::move(value)); - } + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } - template - void insert_multi(InputIterator first, InputIterator last) { - size_type n = mystl::distance(first, last); - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, - "rb_tree's size too big"); - for (; n > 0; --n, ++first) - insert_multi(end(), *first); - } + const_reverse_iterator crend() const noexcept { + return rend(); + } - mystl::pair insert_unique(const value_type &value); - mystl::pair insert_unique(value_type &&value) { - return emplace_unique(mystl::move(value)); - } + // 容量相关操作 - iterator insert_unique(iterator hint, const value_type &value) { - return emplace_unique_use_hint(hint, value); - } - iterator insert_unique(iterator hint, value_type &&value) { - return emplace_unique_use_hint(hint, mystl::move(value)); - } + bool empty() const noexcept { + return node_count_ == 0; + } - template - void insert_unique(InputIterator first, InputIterator last) { - size_type n = mystl::distance(first, last); - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, - "rb_tree's size too big"); - for (; n > 0; --n, ++first) - insert_unique(end(), *first); - } + size_type size() const noexcept { + return node_count_; + } - // erase + size_type max_size() const noexcept { + return static_cast(-1); + } - iterator erase(iterator hint); + // 插入删除相关操作 - size_type erase_multi(const key_type &key); - size_type erase_unique(const key_type &key); + // emplace - void erase(iterator first, iterator last); + template + iterator emplace_multi(Args&&... args); - void clear(); + template + mystl::pair emplace_unique(Args&&... args); - // rb_tree 相关操作 + template + iterator emplace_multi_use_hint(iterator hint, Args&&... args); - iterator find(const key_type &key); - const_iterator find(const key_type &key) const; + template + iterator emplace_unique_use_hint(iterator hint, Args&&... args); - size_type count_multi(const key_type &key) const { - auto p = equal_range_multi(key); - return static_cast(mystl::distance(p.first, p.second)); - } - size_type count_unique(const key_type &key) const { - return find(key) != end() ? 1 : 0; - } + // insert - iterator lower_bound(const key_type &key); - const_iterator lower_bound(const key_type &key) const; + iterator insert_multi(const value_type& value); - iterator upper_bound(const key_type &key); - const_iterator upper_bound(const key_type &key) const; + iterator insert_multi(value_type&& value) { + return emplace_multi(mystl::move(value)); + } - mystl::pair equal_range_multi(const key_type &key) { - return mystl::pair(lower_bound(key), - upper_bound(key)); - } - mystl::pair - equal_range_multi(const key_type &key) const { - return mystl::pair( - lower_bound(key), upper_bound(key)); - } + iterator insert_multi(iterator hint, const value_type& value) { + return emplace_multi_use_hint(hint, value); + } - mystl::pair - equal_range_unique(const key_type &key) { - iterator it = find(key); - auto next = it; - return it == end() ? mystl::make_pair(it, it) - : mystl::make_pair(it, ++next); - } - mystl::pair - equal_range_unique(const key_type &key) const { - const_iterator it = find(key); - auto next = it; - return it == end() ? mystl::make_pair(it, it) - : mystl::make_pair(it, ++next); - } + iterator insert_multi(iterator hint, value_type&& value) { + return emplace_multi_use_hint(hint, mystl::move(value)); + } - void swap(rb_tree &rhs) noexcept; - - private: - // node related - template - node_ptr create_node(Args &&...args); - node_ptr clone_node(base_ptr x); - void destroy_node(node_ptr p); - - // init / reset - void rb_tree_init(); - void reset(); - - // get insert pos - mystl::pair get_insert_multi_pos(const key_type &key); - mystl::pair, bool> - get_insert_unique_pos(const key_type &key); - - // insert value / insert node - iterator insert_value_at(base_ptr x, const value_type &value, - bool add_to_left); - iterator insert_node_at(base_ptr x, node_ptr node, bool add_to_left); - - // insert use hint - iterator insert_multi_use_hint(iterator hint, key_type key, - node_ptr node); - iterator insert_unique_use_hint(iterator hint, key_type key, - node_ptr node); - - // copy tree / erase tree - base_ptr copy_from(base_ptr x, base_ptr p); - void erase_since(base_ptr x); - }; - - /*****************************************************************************************/ - - // 复制构造函数 - template - rb_tree::rb_tree(const rb_tree &rhs) { - rb_tree_init(); - if (rhs.node_count_ != 0) { - root() = copy_from(rhs.root(), header_); - leftmost() = rb_tree_min(root()); - rightmost() = rb_tree_max(root()); + template + void insert_multi(InputIterator first, InputIterator last) { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, + "rb_tree's size too big"); + for (; n > 0; --n, ++first) { + insert_multi(end(), *first); } - node_count_ = rhs.node_count_; - key_comp_ = rhs.key_comp_; } - // 移动构造函数 - template - rb_tree::rb_tree(rb_tree &&rhs) noexcept - : header_(mystl::move(rhs.header_)), node_count_(rhs.node_count_), - key_comp_(rhs.key_comp_) { - rhs.reset(); + mystl::pair insert_unique(const value_type& value); + + mystl::pair insert_unique(value_type&& value) { + return emplace_unique(mystl::move(value)); } - // 复制赋值操作符 - template - rb_tree &rb_tree::operator=(const rb_tree &rhs) { - if (this != &rhs) { - clear(); + iterator insert_unique(iterator hint, const value_type& value) { + return emplace_unique_use_hint(hint, value); + } - if (rhs.node_count_ != 0) { - root() = copy_from(rhs.root(), header_); - leftmost() = rb_tree_min(root()); - rightmost() = rb_tree_max(root()); - } + iterator insert_unique(iterator hint, value_type&& value) { + return emplace_unique_use_hint(hint, mystl::move(value)); + } - node_count_ = rhs.node_count_; - key_comp_ = rhs.key_comp_; + template + void insert_unique(InputIterator first, InputIterator last) { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, + "rb_tree's size too big"); + for (; n > 0; --n, ++first) { + insert_unique(end(), *first); } - return *this; } - // 移动赋值操作符 - template - rb_tree &rb_tree::operator=(rb_tree &&rhs) { - clear(); - header_ = mystl::move(rhs.header_); - node_count_ = rhs.node_count_; - key_comp_ = rhs.key_comp_; - rhs.reset(); - return *this; - } + // erase - // 就地插入元素,键值允许重复 - template - template - typename rb_tree::iterator - rb_tree::emplace_multi(Args &&...args) { - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, - "rb_tree's size too big"); - node_ptr np = create_node(mystl::forward(args)...); - auto res = get_insert_multi_pos(value_traits::get_key(np->value)); - return insert_node_at(res.first, np, res.second); + iterator erase(iterator hint); + + size_type erase_multi(const key_type& key); + size_type erase_unique(const key_type& key); + + void erase(iterator first, iterator last); + + void clear(); + + // rb_tree 相关操作 + + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; + + size_type count_multi(const key_type& key) const { + auto p = equal_range_multi(key); + return static_cast(mystl::distance(p.first, p.second)); } - // 就地插入元素,键值不允许重复 - template - template - mystl::pair::iterator, bool> - rb_tree::emplace_unique(Args &&...args) { - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, - "rb_tree's size too big"); - node_ptr np = create_node(mystl::forward(args)...); - auto res = get_insert_unique_pos(value_traits::get_key(np->value)); - if (res.second) { // 插入成功 - return mystl::make_pair( - insert_node_at(res.first.first, np, res.first.second), true); - } - destroy_node(np); - return mystl::make_pair(iterator(res.first.first), false); + size_type count_unique(const key_type& key) const { + return find(key) != end() ? 1 : 0; } - // 就地插入元素,键值允许重复,当 hint - // 位置与插入位置接近时,插入操作的时间复杂度可以降低 - template - template - typename rb_tree::iterator - rb_tree::emplace_multi_use_hint(iterator hint, Args &&...args) { - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, - "rb_tree's size too big"); - node_ptr np = create_node(mystl::forward(args)...); - if (node_count_ == 0) { - return insert_node_at(header_, np, true); - } - key_type key = value_traits::get_key(np->value); - if (hint == begin()) { // 位于 begin 处 - if (key_comp_(key, value_traits::get_key(*hint))) { - return insert_node_at(hint.node, np, true); - } - else { - auto pos = get_insert_multi_pos(key); - return insert_node_at(pos.first, np, pos.second); - } - } - else if (hint == end()) { // 位于 end 处 - if (!key_comp_(key, value_traits::get_key( - rightmost()->get_node_ptr()->value))) { - return insert_node_at(rightmost(), np, false); - } - else { - auto pos = get_insert_multi_pos(key); - return insert_node_at(pos.first, np, pos.second); - } - } - return insert_multi_use_hint(hint, key, np); + iterator lower_bound(const key_type& key); + const_iterator lower_bound(const key_type& key) const; + + iterator upper_bound(const key_type& key); + const_iterator upper_bound(const key_type& key) const; + + mystl::pair equal_range_multi(const key_type& key) { + return mystl::pair(lower_bound(key), + upper_bound(key)); } - // 就地插入元素,键值不允许重复,当 hint - // 位置与插入位置接近时,插入操作的时间复杂度可以降低 - template - template - typename rb_tree::iterator - rb_tree::emplace_unique_use_hint(iterator hint, - Args &&...args) { - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, - "rb_tree's size too big"); - node_ptr np = create_node(mystl::forward(args)...); - if (node_count_ == 0) { - return insert_node_at(header_, np, true); - } - key_type key = value_traits::get_key(np->value); - if (hint == begin()) { // 位于 begin 处 - if (key_comp_(key, value_traits::get_key(*hint))) { - return insert_node_at(hint.node, np, true); - } - else { - auto pos = get_insert_unique_pos(key); - if (!pos.second) { - destroy_node(np); - return pos.first.first; - } - return insert_node_at(pos.first.first, np, pos.first.second); - } - } - else if (hint == end()) { // 位于 end 处 - if (key_comp_( - value_traits::get_key(rightmost()->get_node_ptr()->value), - key)) { - return insert_node_at(rightmost(), np, false); - } - else { - auto pos = get_insert_unique_pos(key); - if (!pos.second) { - destroy_node(np); - return pos.first.first; - } - return insert_node_at(pos.first.first, np, pos.first.second); - } - } - return insert_unique_use_hint(hint, key, np); + mystl::pair + equal_range_multi(const key_type& key) const { + return mystl::pair(lower_bound(key), + upper_bound(key)); } - // 插入元素,节点键值允许重复 - template - typename rb_tree::iterator - rb_tree::insert_multi(const value_type &value) { - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, - "rb_tree's size too big"); - auto res = get_insert_multi_pos(value_traits::get_key(value)); - return insert_value_at(res.first, value, res.second); + mystl::pair equal_range_unique(const key_type& key) { + iterator it = find(key); + auto next = it; + return it == end() ? mystl::make_pair(it, it) + : mystl::make_pair(it, ++next); } - // 插入新值,节点键值不允许重复,返回一个 pair,若插入成功,pair - // 的第二参数为 true,否则为 false - template - mystl::pair::iterator, bool> - rb_tree::insert_unique(const value_type &value) { - THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, - "rb_tree's size too big"); - auto res = get_insert_unique_pos(value_traits::get_key(value)); - if (res.second) { // 插入成功 - return mystl::make_pair( - insert_value_at(res.first.first, value, res.first.second), - true); - } - return mystl::make_pair(res.first.first, false); + mystl::pair + equal_range_unique(const key_type& key) const { + const_iterator it = find(key); + auto next = it; + return it == end() ? mystl::make_pair(it, it) + : mystl::make_pair(it, ++next); } - // 删除 hint 位置的节点 - template - typename rb_tree::iterator - rb_tree::erase(iterator hint) { - auto node = hint.node->get_node_ptr(); - iterator next(node); - ++next; + void swap(rb_tree& rhs) noexcept; - rb_tree_erase_rebalance(hint.node, root(), leftmost(), rightmost()); - destroy_node(node); - --node_count_; - return next; - } - - // 删除键值等于 key 的元素,返回删除的个数 - template - typename rb_tree::size_type - rb_tree::erase_multi(const key_type &key) { - auto p = equal_range_multi(key); - size_type n = mystl::distance(p.first, p.second); - erase(p.first, p.second); - return n; - } - - // 删除键值等于 key 的元素,返回删除的个数 - template - typename rb_tree::size_type - rb_tree::erase_unique(const key_type &key) { - auto it = find(key); - if (it != end()) { - erase(it); - return 1; - } - return 0; +private: + // node related + template + node_ptr create_node(Args&&... args); + node_ptr clone_node(base_ptr x); + void destroy_node(node_ptr p); + + // init / reset + void rb_tree_init(); + void reset(); + + // get insert pos + mystl::pair get_insert_multi_pos(const key_type& key); + mystl::pair, bool> + get_insert_unique_pos(const key_type& key); + + // insert value / insert node + iterator + insert_value_at(base_ptr x, const value_type& value, bool add_to_left); + iterator insert_node_at(base_ptr x, node_ptr node, bool add_to_left); + + // insert use hint + iterator insert_multi_use_hint(iterator hint, key_type key, node_ptr node); + iterator insert_unique_use_hint(iterator hint, key_type key, node_ptr node); + + // copy tree / erase tree + base_ptr copy_from(base_ptr x, base_ptr p); + void erase_since(base_ptr x); +}; + +/*****************************************************************************************/ + +// 复制构造函数 +template +rb_tree::rb_tree(const rb_tree& rhs) { + rb_tree_init(); + if (rhs.node_count_ != 0) { + root() = copy_from(rhs.root(), header_); + leftmost() = rb_tree_min(root()); + rightmost() = rb_tree_max(root()); } + node_count_ = rhs.node_count_; + key_comp_ = rhs.key_comp_; +} + +// 移动构造函数 +template +rb_tree::rb_tree(rb_tree&& rhs) noexcept + : header_(mystl::move(rhs.header_)), + node_count_(rhs.node_count_), + key_comp_(rhs.key_comp_) { + rhs.reset(); +} + +// 复制赋值操作符 +template +rb_tree& rb_tree::operator=(const rb_tree& rhs) { + if (this != &rhs) { + clear(); - // 删除[first, last)区间内的元素 - template - void rb_tree::erase(iterator first, iterator last) { - if (first == begin() && last == end()) { - clear(); + if (rhs.node_count_ != 0) { + root() = copy_from(rhs.root(), header_); + leftmost() = rb_tree_min(root()); + rightmost() = rb_tree_max(root()); + } + + node_count_ = rhs.node_count_; + key_comp_ = rhs.key_comp_; + } + return *this; +} + +// 移动赋值操作符 +template +rb_tree& rb_tree::operator=(rb_tree&& rhs) { + clear(); + header_ = mystl::move(rhs.header_); + node_count_ = rhs.node_count_; + key_comp_ = rhs.key_comp_; + rhs.reset(); + return *this; +} + +// 就地插入元素,键值允许重复 +template +template +typename rb_tree::iterator +rb_tree::emplace_multi(Args&&... args) { + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, + "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + auto res = get_insert_multi_pos(value_traits::get_key(np->value)); + return insert_node_at(res.first, np, res.second); +} + +// 就地插入元素,键值不允许重复 +template +template +mystl::pair::iterator, bool> +rb_tree::emplace_unique(Args&&... args) { + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, + "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + auto res = get_insert_unique_pos(value_traits::get_key(np->value)); + if (res.second) { // 插入成功 + return mystl::make_pair(insert_node_at(res.first.first, np, + res.first.second), + true); + } + destroy_node(np); + return mystl::make_pair(iterator(res.first.first), false); +} + +// 就地插入元素,键值允许重复,当 hint +// 位置与插入位置接近时,插入操作的时间复杂度可以降低 +template +template +typename rb_tree::iterator +rb_tree::emplace_multi_use_hint(iterator hint, Args&&... args) { + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, + "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + if (node_count_ == 0) { + return insert_node_at(header_, np, true); + } + key_type key = value_traits::get_key(np->value); + if (hint == begin()) { // 位于 begin 处 + if (key_comp_(key, value_traits::get_key(*hint))) { + return insert_node_at(hint.node, np, true); } else { - while (first != last) - erase(first++); + auto pos = get_insert_multi_pos(key); + return insert_node_at(pos.first, np, pos.second); } } - - // 清空 rb tree - template - void rb_tree::clear() { - if (node_count_ != 0) { - erase_since(root()); - leftmost() = header_; - root() = nullptr; - rightmost() = header_; - node_count_ = 0; + else if (hint == end()) { // 位于 end 处 + if (!key_comp_( + key, value_traits::get_key(rightmost()->get_node_ptr()->value))) { + return insert_node_at(rightmost(), np, false); } - } - - // 查找键值为 k 的节点,返回指向它的迭代器 - template - typename rb_tree::iterator - rb_tree::find(const key_type &key) { - auto y = header_; // 最后一个不小于 key 的节点 - auto x = root(); - while (x != nullptr) { - if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), - key)) { // key 小于等于 x 键值,向左走 - y = x, x = x->left; - } - else { // key 大于 x 键值,向右走 - x = x->right; - } + else { + auto pos = get_insert_multi_pos(key); + return insert_node_at(pos.first, np, pos.second); } - iterator j = iterator(y); - return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() - : j; } - - template - typename rb_tree::const_iterator - rb_tree::find(const key_type &key) const { - auto y = header_; // 最后一个不小于 key 的节点 - auto x = root(); - while (x != nullptr) { - if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), - key)) { // key 小于等于 x 键值,向左走 - y = x, x = x->left; - } - else { // key 大于 x 键值,向右走 - x = x->right; - } - } - const_iterator j = const_iterator(y); - return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() - : j; + return insert_multi_use_hint(hint, key, np); +} + +// 就地插入元素,键值不允许重复,当 hint +// 位置与插入位置接近时,插入操作的时间复杂度可以降低 +template +template +typename rb_tree::iterator +rb_tree::emplace_unique_use_hint(iterator hint, Args&&... args) { + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, + "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + if (node_count_ == 0) { + return insert_node_at(header_, np, true); } - - // 键值不小于 key 的第一个位置 - template - typename rb_tree::iterator - rb_tree::lower_bound(const key_type &key) { - auto y = header_; - auto x = root(); - while (x != nullptr) { - if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), - key)) { // key <= x - y = x, x = x->left; - } - else { - x = x->right; - } + key_type key = value_traits::get_key(np->value); + if (hint == begin()) { // 位于 begin 处 + if (key_comp_(key, value_traits::get_key(*hint))) { + return insert_node_at(hint.node, np, true); } - return iterator(y); - } - - template - typename rb_tree::const_iterator - rb_tree::lower_bound(const key_type &key) const { - auto y = header_; - auto x = root(); - while (x != nullptr) { - if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), - key)) { // key <= x - y = x, x = x->left; - } - else { - x = x->right; + else { + auto pos = get_insert_unique_pos(key); + if (!pos.second) { + destroy_node(np); + return pos.first.first; } + return insert_node_at(pos.first.first, np, pos.first.second); } - return const_iterator(y); } - - // 键值不小于 key 的最后一个位置 - template - typename rb_tree::iterator - rb_tree::upper_bound(const key_type &key) { - auto y = header_; - auto x = root(); - while (x != nullptr) { - if (key_comp_(key, value_traits::get_key( - x->get_node_ptr()->value))) { // key < x - y = x, x = x->left; - } - else { - x = x->right; - } + else if (hint == end()) { // 位于 end 处 + if (key_comp_(value_traits::get_key(rightmost()->get_node_ptr()->value), + key)) { + return insert_node_at(rightmost(), np, false); } - return iterator(y); - } - - template - typename rb_tree::const_iterator - rb_tree::upper_bound(const key_type &key) const { - auto y = header_; - auto x = root(); - while (x != nullptr) { - if (key_comp_(key, value_traits::get_key( - x->get_node_ptr()->value))) { // key < x - y = x, x = x->left; - } - else { - x = x->right; + else { + auto pos = get_insert_unique_pos(key); + if (!pos.second) { + destroy_node(np); + return pos.first.first; } + return insert_node_at(pos.first.first, np, pos.first.second); } - return const_iterator(y); } - - // 交换 rb tree - template - void rb_tree::swap(rb_tree &rhs) noexcept { - if (this != &rhs) { - mystl::swap(header_, rhs.header_); - mystl::swap(node_count_, rhs.node_count_); - mystl::swap(key_comp_, rhs.key_comp_); - } + return insert_unique_use_hint(hint, key, np); +} + +// 插入元素,节点键值允许重复 +template +typename rb_tree::iterator +rb_tree::insert_multi(const value_type& value) { + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, + "rb_tree's size too big"); + auto res = get_insert_multi_pos(value_traits::get_key(value)); + return insert_value_at(res.first, value, res.second); +} + +// 插入新值,节点键值不允许重复,返回一个 pair,若插入成功,pair +// 的第二参数为 true,否则为 false +template +mystl::pair::iterator, bool> +rb_tree::insert_unique(const value_type& value) { + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, + "rb_tree's size too big"); + auto res = get_insert_unique_pos(value_traits::get_key(value)); + if (res.second) { // 插入成功 + return mystl::make_pair(insert_value_at(res.first.first, value, + res.first.second), + true); } - - /*****************************************************************************************/ - // helper function - - // 创建一个结点 - template - template - typename rb_tree::node_ptr - rb_tree::create_node(Args &&...args) { - auto tmp = node_allocator::allocate(1); - try { - data_allocator::construct(mystl::address_of(tmp->value), - mystl::forward(args)...); - tmp->left = nullptr; - tmp->right = nullptr; - tmp->parent = nullptr; - } catch (...) { - node_allocator::deallocate(tmp); - throw; - } - return tmp; + return mystl::make_pair(res.first.first, false); +} + +// 删除 hint 位置的节点 +template +typename rb_tree::iterator +rb_tree::erase(iterator hint) { + auto node = hint.node->get_node_ptr(); + iterator next(node); + ++next; + + rb_tree_erase_rebalance(hint.node, root(), leftmost(), rightmost()); + destroy_node(node); + --node_count_; + return next; +} + +// 删除键值等于 key 的元素,返回删除的个数 +template +typename rb_tree::size_type +rb_tree::erase_multi(const key_type& key) { + auto p = equal_range_multi(key); + size_type n = mystl::distance(p.first, p.second); + erase(p.first, p.second); + return n; +} + +// 删除键值等于 key 的元素,返回删除的个数 +template +typename rb_tree::size_type +rb_tree::erase_unique(const key_type& key) { + auto it = find(key); + if (it != end()) { + erase(it); + return 1; } + return 0; +} - // 复制一个结点 - template - typename rb_tree::node_ptr - rb_tree::clone_node(base_ptr x) { - node_ptr tmp = create_node(x->get_node_ptr()->value); - tmp->color = x->color; - tmp->left = nullptr; - tmp->right = nullptr; - return tmp; +// 删除[first, last)区间内的元素 +template +void rb_tree::erase(iterator first, iterator last) { + if (first == begin() && last == end()) { + clear(); } - - // 销毁一个结点 - template - void rb_tree::destroy_node(node_ptr p) { - data_allocator::destroy(&p->value); - node_allocator::deallocate(p); + else { + while (first != last) { + erase(first++); + } } +} - // 初始化容器 - template - void rb_tree::rb_tree_init() { - header_ = base_allocator::allocate(1); - header_->color = rb_tree_red; // header_ 节点颜色为红,与 root 区分 - root() = nullptr; +// 清空 rb tree +template +void rb_tree::clear() { + if (node_count_ != 0) { + erase_since(root()); leftmost() = header_; + root() = nullptr; rightmost() = header_; node_count_ = 0; } - - // reset 函数 - template - void rb_tree::reset() { - header_ = nullptr; - node_count_ = 0; +} + +// 查找键值为 k 的节点,返回指向它的迭代器 +template +typename rb_tree::iterator +rb_tree::find(const key_type& key) { + auto y = header_; // 最后一个不小于 key 的节点 + auto x = root(); + while (x != nullptr) { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), + key)) { // key 小于等于 x 键值,向左走 + y = x, x = x->left; + } + else { // key 大于 x 键值,向右走 + x = x->right; + } } - - // get_insert_multi_pos 函数 - template - mystl::pair::base_ptr, bool> - rb_tree::get_insert_multi_pos(const key_type &key) { - auto x = root(); - auto y = header_; - bool add_to_left = true; - while (x != nullptr) { - y = x; - add_to_left = - key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)); - x = add_to_left ? x->left : x->right; + iterator j = iterator(y); + return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() + : j; +} + +template +typename rb_tree::const_iterator +rb_tree::find(const key_type& key) const { + auto y = header_; // 最后一个不小于 key 的节点 + auto x = root(); + while (x != nullptr) { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), + key)) { // key 小于等于 x 键值,向左走 + y = x, x = x->left; + } + else { // key 大于 x 键值,向右走 + x = x->right; } - return mystl::make_pair(y, add_to_left); - } - - // get_insert_unique_pos 函数 - template - mystl::pair::base_ptr, bool>, bool> - rb_tree::get_insert_unique_pos( - const key_type - &key) { // 返回一个 pair,第一个值为一个 - // pair,包含插入点的父节点和一个 bool 表示是否在左边插入, - // 第二个值为一个 bool,表示是否插入成功 - auto x = root(); - auto y = header_; - bool add_to_left = true; // 树为空时也在 header_ 左边插入 - while (x != nullptr) { - y = x; - add_to_left = - key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)); - x = add_to_left ? x->left : x->right; + } + const_iterator j = const_iterator(y); + return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() + : j; +} + +// 键值不小于 key 的第一个位置 +template +typename rb_tree::iterator +rb_tree::lower_bound(const key_type& key) { + auto y = header_; + auto x = root(); + while (x != nullptr) { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), + key)) { // key <= x + y = x, x = x->left; } - iterator j = iterator(y); // 此时 y 为插入点的父节点 - if (add_to_left) { - if (y == header_ || - j == - begin()) { // 如果树为空树或插入点在最左节点处,肯定可以插入新的节点 - return mystl::make_pair(mystl::make_pair(y, true), true); - } - else { // 否则,如果存在重复节点,那么 --j 就是重复的值 - --j; - } + else { + x = x->right; } - if (key_comp_(value_traits::get_key(*j), key)) { // 表明新节点没有重复 - return mystl::make_pair(mystl::make_pair(y, add_to_left), true); + } + return iterator(y); +} + +template +typename rb_tree::const_iterator +rb_tree::lower_bound(const key_type& key) const { + auto y = header_; + auto x = root(); + while (x != nullptr) { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), + key)) { // key <= x + y = x, x = x->left; } - // 进行至此,表示新节点与现有节点键值重复 - return mystl::make_pair(mystl::make_pair(y, add_to_left), false); - } - - // insert_value_at 函数 - // x 为插入点的父节点, value 为要插入的值,add_to_left 表示是否在左边插入 - template - typename rb_tree::iterator - rb_tree::insert_value_at(base_ptr x, const value_type &value, - bool add_to_left) { - node_ptr node = create_node(value); - node->parent = x; - auto base_node = node->get_base_ptr(); - if (x == header_) { - root() = base_node; - leftmost() = base_node; - rightmost() = base_node; + else { + x = x->right; } - else if (add_to_left) { - x->left = base_node; - if (leftmost() == x) - leftmost() = base_node; + } + return const_iterator(y); +} + +// 键值不小于 key 的最后一个位置 +template +typename rb_tree::iterator +rb_tree::upper_bound(const key_type& key) { + auto y = header_; + auto x = root(); + while (x != nullptr) { + if (key_comp_(key, value_traits::get_key( + x->get_node_ptr()->value))) { // key < x + y = x, x = x->left; } else { - x->right = base_node; - if (rightmost() == x) - rightmost() = base_node; - } - rb_tree_insert_rebalance(base_node, root()); - ++node_count_; - return iterator(node); - } - - // 在 x 节点处插入新的节点 - // x 为插入点的父节点, node 为要插入的节点,add_to_left 表示是否在左边插入 - template - typename rb_tree::iterator - rb_tree::insert_node_at(base_ptr x, node_ptr node, - bool add_to_left) { - node->parent = x; - auto base_node = node->get_base_ptr(); - if (x == header_) { - root() = base_node; - leftmost() = base_node; - rightmost() = base_node; + x = x->right; } - else if (add_to_left) { - x->left = base_node; - if (leftmost() == x) - leftmost() = base_node; + } + return iterator(y); +} + +template +typename rb_tree::const_iterator +rb_tree::upper_bound(const key_type& key) const { + auto y = header_; + auto x = root(); + while (x != nullptr) { + if (key_comp_(key, value_traits::get_key( + x->get_node_ptr()->value))) { // key < x + y = x, x = x->left; } else { - x->right = base_node; - if (rightmost() == x) - rightmost() = base_node; - } - rb_tree_insert_rebalance(base_node, root()); - ++node_count_; - return iterator(node); - } - - // 插入元素,键值允许重复,使用 hint - template - typename rb_tree::iterator - rb_tree::insert_multi_use_hint(iterator hint, key_type key, - node_ptr node) { - // 在 hint 附近寻找可插入的位置 - auto np = hint.node; - auto before = hint; - --before; - auto bnp = before.node; - if (!key_comp_(key, value_traits::get_key(*before)) && - !key_comp_(value_traits::get_key(*hint), - key)) { // before <= node <= hint - if (bnp->right == nullptr) { - return insert_node_at(bnp, node, false); - } - else if (np->left == nullptr) { - return insert_node_at(np, node, true); - } + x = x->right; } - auto pos = get_insert_multi_pos(key); - return insert_node_at(pos.first, node, pos.second); - } - - // 插入元素,键值不允许重复,使用 hint - template - typename rb_tree::iterator - rb_tree::insert_unique_use_hint(iterator hint, key_type key, - node_ptr node) { - // 在 hint 附近寻找可插入的位置 - auto np = hint.node; - auto before = hint; - --before; - auto bnp = before.node; - if (key_comp_(value_traits::get_key(*before), key) && - key_comp_(key, - value_traits::get_key(*hint))) { // before < node < hint - if (bnp->right == nullptr) { - return insert_node_at(bnp, node, false); - } - else if (np->left == nullptr) { - return insert_node_at(np, node, true); - } + } + return const_iterator(y); +} + +// 交换 rb tree +template +void rb_tree::swap(rb_tree& rhs) noexcept { + if (this != &rhs) { + mystl::swap(header_, rhs.header_); + mystl::swap(node_count_, rhs.node_count_); + mystl::swap(key_comp_, rhs.key_comp_); + } +} + +/*****************************************************************************************/ +// helper function + +// 创建一个结点 +template +template +typename rb_tree::node_ptr +rb_tree::create_node(Args&&... args) { + auto tmp = node_allocator::allocate(1); + try { + data_allocator::construct(mystl::address_of(tmp->value), + mystl::forward(args)...); + tmp->left = nullptr; + tmp->right = nullptr; + tmp->parent = nullptr; + } catch (...) { + node_allocator::deallocate(tmp); + throw; + } + return tmp; +} + +// 复制一个结点 +template +typename rb_tree::node_ptr +rb_tree::clone_node(base_ptr x) { + node_ptr tmp = create_node(x->get_node_ptr()->value); + tmp->color = x->color; + tmp->left = nullptr; + tmp->right = nullptr; + return tmp; +} + +// 销毁一个结点 +template +void rb_tree::destroy_node(node_ptr p) { + data_allocator::destroy(&p->value); + node_allocator::deallocate(p); +} + +// 初始化容器 +template +void rb_tree::rb_tree_init() { + header_ = base_allocator::allocate(1); + header_->color = rb_tree_red; // header_ 节点颜色为红,与 root 区分 + root() = nullptr; + leftmost() = header_; + rightmost() = header_; + node_count_ = 0; +} + +// reset 函数 +template +void rb_tree::reset() { + header_ = nullptr; + node_count_ = 0; +} + +// get_insert_multi_pos 函数 +template +mystl::pair::base_ptr, bool> +rb_tree::get_insert_multi_pos(const key_type& key) { + auto x = root(); + auto y = header_; + bool add_to_left = true; + while (x != nullptr) { + y = x; + add_to_left + = key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)); + x = add_to_left ? x->left : x->right; + } + return mystl::make_pair(y, add_to_left); +} + +// get_insert_unique_pos 函数 +template +mystl::pair::base_ptr, bool>, bool> +rb_tree::get_insert_unique_pos( + const key_type& + key) { // 返回一个 pair,第一个值为一个 + // pair,包含插入点的父节点和一个 bool 表示是否在左边插入, + // 第二个值为一个 bool,表示是否插入成功 + auto x = root(); + auto y = header_; + bool add_to_left = true; // 树为空时也在 header_ 左边插入 + while (x != nullptr) { + y = x; + add_to_left + = key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)); + x = add_to_left ? x->left : x->right; + } + iterator j = iterator(y); // 此时 y 为插入点的父节点 + if (add_to_left) { + if ( + y == header_ + || j == begin()) { // 如果树为空树或插入点在最左节点处,肯定可以插入新的节点 + return mystl::make_pair(mystl::make_pair(y, true), true); } - auto pos = get_insert_unique_pos(key); - if (!pos.second) { - destroy_node(node); - return pos.first.first; + else { // 否则,如果存在重复节点,那么 --j 就是重复的值 + --j; } - return insert_node_at(pos.first.first, node, pos.first.second); - } - - // copy_from 函数 - // 递归复制一颗树,节点从 x 开始,p 为 x 的父节点 - template - typename rb_tree::base_ptr - rb_tree::copy_from(base_ptr x, base_ptr p) { - auto top = clone_node(x); - top->parent = p; - try { - if (x->right) - top->right = copy_from(x->right, top); - p = top; - x = x->left; - while (x != nullptr) { - auto y = clone_node(x); - p->left = y; - y->parent = p; - if (x->right) - y->right = copy_from(x->right, y); - p = y; - x = x->left; - } - } catch (...) { - erase_since(top); - throw; + } + if (key_comp_(value_traits::get_key(*j), key)) { // 表明新节点没有重复 + return mystl::make_pair(mystl::make_pair(y, add_to_left), true); + } + // 进行至此,表示新节点与现有节点键值重复 + return mystl::make_pair(mystl::make_pair(y, add_to_left), false); +} + +// insert_value_at 函数 +// x 为插入点的父节点, value 为要插入的值,add_to_left 表示是否在左边插入 +template +typename rb_tree::iterator +rb_tree::insert_value_at(base_ptr x, const value_type& value, + bool add_to_left) { + node_ptr node = create_node(value); + node->parent = x; + auto base_node = node->get_base_ptr(); + if (x == header_) { + root() = base_node; + leftmost() = base_node; + rightmost() = base_node; + } + else if (add_to_left) { + x->left = base_node; + if (leftmost() == x) { + leftmost() = base_node; } - return top; } - - // erase_since 函数 - // 从 x 节点开始删除该节点及其子树 - template - void rb_tree::erase_since(base_ptr x) { - while (x != nullptr) { - erase_since(x->right); - auto y = x->left; - destroy_node(x->get_node_ptr()); - x = y; + else { + x->right = base_node; + if (rightmost() == x) { + rightmost() = base_node; } } - - // 重载比较操作符 - template - bool operator==(const rb_tree &lhs, - const rb_tree &rhs) { - return lhs.size() == rhs.size() && - mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); + rb_tree_insert_rebalance(base_node, root()); + ++node_count_; + return iterator(node); +} + +// 在 x 节点处插入新的节点 +// x 为插入点的父节点, node 为要插入的节点,add_to_left 表示是否在左边插入 +template +typename rb_tree::iterator +rb_tree::insert_node_at(base_ptr x, node_ptr node, + bool add_to_left) { + node->parent = x; + auto base_node = node->get_base_ptr(); + if (x == header_) { + root() = base_node; + leftmost() = base_node; + rightmost() = base_node; } - - template - bool operator<(const rb_tree &lhs, - const rb_tree &rhs) { - return mystl::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end()); + else if (add_to_left) { + x->left = base_node; + if (leftmost() == x) { + leftmost() = base_node; + } } - - template - bool operator!=(const rb_tree &lhs, - const rb_tree &rhs) { - return !(lhs == rhs); + else { + x->right = base_node; + if (rightmost() == x) { + rightmost() = base_node; + } } - - template - bool operator>(const rb_tree &lhs, - const rb_tree &rhs) { - return rhs < lhs; + rb_tree_insert_rebalance(base_node, root()); + ++node_count_; + return iterator(node); +} + +// 插入元素,键值允许重复,使用 hint +template +typename rb_tree::iterator +rb_tree::insert_multi_use_hint(iterator hint, key_type key, + node_ptr node) { + // 在 hint 附近寻找可插入的位置 + auto np = hint.node; + auto before = hint; + --before; + auto bnp = before.node; + if (!key_comp_(key, value_traits::get_key(*before)) + && !key_comp_(value_traits::get_key(*hint), + key)) { // before <= node <= hint + if (bnp->right == nullptr) { + return insert_node_at(bnp, node, false); + } + else if (np->left == nullptr) { + return insert_node_at(np, node, true); + } } - - template - bool operator<=(const rb_tree &lhs, - const rb_tree &rhs) { - return !(rhs < lhs); + auto pos = get_insert_multi_pos(key); + return insert_node_at(pos.first, node, pos.second); +} + +// 插入元素,键值不允许重复,使用 hint +template +typename rb_tree::iterator +rb_tree::insert_unique_use_hint(iterator hint, key_type key, + node_ptr node) { + // 在 hint 附近寻找可插入的位置 + auto np = hint.node; + auto before = hint; + --before; + auto bnp = before.node; + if (key_comp_(value_traits::get_key(*before), key) + && key_comp_(key, + value_traits::get_key(*hint))) { // before < node < hint + if (bnp->right == nullptr) { + return insert_node_at(bnp, node, false); + } + else if (np->left == nullptr) { + return insert_node_at(np, node, true); + } } - - template - bool operator>=(const rb_tree &lhs, - const rb_tree &rhs) { - return !(lhs < rhs); + auto pos = get_insert_unique_pos(key); + if (!pos.second) { + destroy_node(node); + return pos.first.first; } - - // 重载 mystl 的 swap - template - void swap(rb_tree &lhs, rb_tree &rhs) noexcept { - lhs.swap(rhs); + return insert_node_at(pos.first.first, node, pos.first.second); +} + +// copy_from 函数 +// 递归复制一颗树,节点从 x 开始,p 为 x 的父节点 +template +typename rb_tree::base_ptr +rb_tree::copy_from(base_ptr x, base_ptr p) { + auto top = clone_node(x); + top->parent = p; + try { + if (x->right) { + top->right = copy_from(x->right, top); + } + p = top; + x = x->left; + while (x != nullptr) { + auto y = clone_node(x); + p->left = y; + y->parent = p; + if (x->right) { + y->right = copy_from(x->right, y); + } + p = y; + x = x->left; + } + } catch (...) { + erase_since(top); + throw; } - -}; - -#endif /* _RB_TREE_ */ + return top; +} + +// erase_since 函数 +// 从 x 节点开始删除该节点及其子树 +template +void rb_tree::erase_since(base_ptr x) { + while (x != nullptr) { + erase_since(x->right); + auto y = x->left; + destroy_node(x->get_node_ptr()); + x = y; + } +} + +// 重载比较操作符 +template +bool operator==(const rb_tree& lhs, + const rb_tree& rhs) { + return lhs.size() == rhs.size() + && mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator<(const rb_tree& lhs, const rb_tree& rhs) { + return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), + rhs.end()); +} + +template +bool operator!=(const rb_tree& lhs, + const rb_tree& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const rb_tree& lhs, const rb_tree& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const rb_tree& lhs, + const rb_tree& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const rb_tree& lhs, + const rb_tree& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(rb_tree& lhs, rb_tree& rhs) noexcept { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_RB_TREE */ diff --git a/src/libcxx/include/set b/src/libcxx/include/set index a0252c23b..e73fb1e2f 100644 --- a/src/libcxx/include/set +++ b/src/libcxx/include/set @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// set for Simple-XX/SimpleKernel. - -#ifndef _SET_ -#define _SET_ +/** + * @file set + * @brief stl set 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_SET +#define SIMPLEKERNEL_SET // 这个头文件包含两个模板类 set 和 multiset // set : 集合,键值即实值,集合内元素会自动排序,键值不允许重复 @@ -24,534 +35,577 @@ namespace mystl { - // 模板类 set,键值不允许重复 - // 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less - template > - class set { - public: - typedef Key key_type; - typedef Key value_type; - typedef Compare key_compare; - typedef Compare value_compare; - - private: - // 以 mystl::rb_tree 作为底层机制 - typedef mystl::rb_tree base_type; - base_type tree_; - - public: - // 使用 rb_tree 定义的型别 - typedef typename base_type::node_type node_type; - typedef typename base_type::const_pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::const_reference reference; - typedef typename base_type::const_reference const_reference; - typedef typename base_type::const_iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::const_reverse_iterator reverse_iterator; - typedef - typename base_type::const_reverse_iterator const_reverse_iterator; - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::allocator_type allocator_type; - - public: - // 构造、复制、移动函数 - set() = default; - - template - set(InputIterator first, InputIterator last) : tree_() { - tree_.insert_unique(first, last); - } - set(std::initializer_list ilist) : tree_() { - tree_.insert_unique(ilist.begin(), ilist.end()); - } - - set(const set &rhs) : tree_(rhs.tree_) { - } - set(set &&rhs) noexcept : tree_(mystl::move(rhs.tree_)) { - } - - set &operator=(const set &rhs) { - tree_ = rhs.tree_; - return *this; - } - set &operator=(set &&rhs) { - tree_ = mystl::move(rhs.tree_); - return *this; - } - set &operator=(std::initializer_list ilist) { - tree_.clear(); - tree_.insert_unique(ilist.begin(), ilist.end()); - return *this; - } - - // 相关接口 - - key_compare key_comp() const { - return tree_.key_comp(); - } - value_compare value_comp() const { - return tree_.key_comp(); - } - allocator_type get_allocator() const { - return tree_.get_allocator(); - } - - // 迭代器相关 - - iterator begin() noexcept { - return tree_.begin(); - } - const_iterator begin() const noexcept { - return tree_.begin(); - } - iterator end() noexcept { - return tree_.end(); - } - const_iterator end() const noexcept { - return tree_.end(); - } - - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } - - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } - - // 容量相关 - bool empty() const noexcept { - return tree_.empty(); - } - size_type size() const noexcept { - return tree_.size(); - } - size_type max_size() const noexcept { - return tree_.max_size(); - } - - // 插入删除操作 - - template - pair emplace(Args &&...args) { - return tree_.emplace_unique(mystl::forward(args)...); - } - - template - iterator emplace_hint(iterator hint, Args &&...args) { - return tree_.emplace_unique_use_hint(hint, - mystl::forward(args)...); - } - - pair insert(const value_type &value) { - return tree_.insert_unique(value); - } - pair insert(value_type &&value) { - return tree_.insert_unique(mystl::move(value)); - } - - iterator insert(iterator hint, const value_type &value) { - return tree_.insert_unique(hint, value); - } - iterator insert(iterator hint, value_type &&value) { - return tree_.insert_unique(hint, mystl::move(value)); - } - - template - void insert(InputIterator first, InputIterator last) { - tree_.insert_unique(first, last); - } - - void erase(iterator position) { - tree_.erase(position); - } - size_type erase(const key_type &key) { - return tree_.erase_unique(key); - } - void erase(iterator first, iterator last) { - tree_.erase(first, last); - } - - void clear() { - tree_.clear(); - } - - // set 相关操作 - - iterator find(const key_type &key) { - return tree_.find(key); - } - const_iterator find(const key_type &key) const { - return tree_.find(key); - } - - size_type count(const key_type &key) const { - return tree_.count_unique(key); - } - - iterator lower_bound(const key_type &key) { - return tree_.lower_bound(key); - } - const_iterator lower_bound(const key_type &key) const { - return tree_.lower_bound(key); - } - - iterator upper_bound(const key_type &key) { - return tree_.upper_bound(key); - } - const_iterator upper_bound(const key_type &key) const { - return tree_.upper_bound(key); - } - - pair equal_range(const key_type &key) { - return tree_.equal_range_unique(key); - } - - pair - equal_range(const key_type &key) const { - return tree_.equal_range_unique(key); - } - - void swap(set &rhs) noexcept { - tree_.swap(rhs.tree_); - } - - public: - friend bool operator==(const set &lhs, const set &rhs) { - return lhs.tree_ == rhs.tree_; - } - friend bool operator<(const set &lhs, const set &rhs) { - return lhs.tree_ < rhs.tree_; - } - }; - - // 重载比较操作符 - template - bool operator==(const set &lhs, - const set &rhs) { - return lhs == rhs; - } - - template - bool operator<(const set &lhs, const set &rhs) { - return lhs < rhs; - } - - template - bool operator!=(const set &lhs, - const set &rhs) { - return !(lhs == rhs); - } - - template - bool operator>(const set &lhs, const set &rhs) { - return rhs < lhs; - } - - template - bool operator<=(const set &lhs, - const set &rhs) { - return !(rhs < lhs); - } - - template - bool operator>=(const set &lhs, - const set &rhs) { - return !(lhs < rhs); - } - - // 重载 mystl 的 swap - template - void swap(set &lhs, set &rhs) noexcept { - lhs.swap(rhs); - } - - /*****************************************************************************************/ - - // 模板类 multiset,键值允许重复 - // 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less - template > - class multiset { - public: - typedef Key key_type; - typedef Key value_type; - typedef Compare key_compare; - typedef Compare value_compare; - - private: - // 以 mystl::rb_tree 作为底层机制 - typedef mystl::rb_tree base_type; - base_type tree_; // 以 rb_tree 表现 multiset - - public: - // 使用 rb_tree 定义的型别 - typedef typename base_type::node_type node_type; - typedef typename base_type::const_pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::const_reference reference; - typedef typename base_type::const_reference const_reference; - typedef typename base_type::const_iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::const_reverse_iterator reverse_iterator; - typedef - typename base_type::const_reverse_iterator const_reverse_iterator; - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::allocator_type allocator_type; - - public: - // 构造、复制、移动函数 - multiset() = default; - - template - multiset(InputIterator first, InputIterator last) : tree_() { - tree_.insert_multi(first, last); - } - multiset(std::initializer_list ilist) : tree_() { - tree_.insert_multi(ilist.begin(), ilist.end()); - } - - multiset(const multiset &rhs) : tree_(rhs.tree_) { - } - multiset(multiset &&rhs) noexcept : tree_(mystl::move(rhs.tree_)) { - } - - multiset &operator=(const multiset &rhs) { - tree_ = rhs.tree_; - return *this; - } - multiset &operator=(multiset &&rhs) { - tree_ = mystl::move(rhs.tree_); - return *this; - } - multiset &operator=(std::initializer_list ilist) { - tree_.clear(); - tree_.insert_multi(ilist.begin(), ilist.end()); - return *this; - } - - // 相关接口 - - key_compare key_comp() const { - return tree_.key_comp(); - } - value_compare value_comp() const { - return tree_.key_comp(); - } - allocator_type get_allocator() const { - return tree_.get_allocator(); - } - - // 迭代器相关 - - iterator begin() noexcept { - return tree_.begin(); - } - const_iterator begin() const noexcept { - return tree_.begin(); - } - iterator end() noexcept { - return tree_.end(); - } - const_iterator end() const noexcept { - return tree_.end(); - } - - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } - - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } - - // 容量相关 - bool empty() const noexcept { - return tree_.empty(); - } - size_type size() const noexcept { - return tree_.size(); - } - size_type max_size() const noexcept { - return tree_.max_size(); - } - - // 插入删除操作 - - template - iterator emplace(Args &&...args) { - return tree_.emplace_multi(mystl::forward(args)...); - } - - template - iterator emplace_hint(iterator hint, Args &&...args) { - return tree_.emplace_multi_use_hint(hint, - mystl::forward(args)...); - } - - iterator insert(const value_type &value) { - return tree_.insert_multi(value); - } - iterator insert(value_type &&value) { - return tree_.insert_multi(mystl::move(value)); - } - - iterator insert(iterator hint, const value_type &value) { - return tree_.insert_multi(hint, value); - } - iterator insert(iterator hint, value_type &&value) { - return tree_.insert_multi(hint, mystl::move(value)); - } - - template - void insert(InputIterator first, InputIterator last) { - tree_.insert_multi(first, last); - } - - void erase(iterator position) { - tree_.erase(position); - } - size_type erase(const key_type &key) { - return tree_.erase_multi(key); - } - void erase(iterator first, iterator last) { - tree_.erase(first, last); - } - - void clear() { - tree_.clear(); - } - - // multiset 相关操作 - - iterator find(const key_type &key) { - return tree_.find(key); - } - const_iterator find(const key_type &key) const { - return tree_.find(key); - } - - size_type count(const key_type &key) const { - return tree_.count_multi(key); - } - - iterator lower_bound(const key_type &key) { - return tree_.lower_bound(key); - } - const_iterator lower_bound(const key_type &key) const { - return tree_.lower_bound(key); - } - - iterator upper_bound(const key_type &key) { - return tree_.upper_bound(key); - } - const_iterator upper_bound(const key_type &key) const { - return tree_.upper_bound(key); - } - - pair equal_range(const key_type &key) { - return tree_.equal_range_multi(key); - } - - pair - equal_range(const key_type &key) const { - return tree_.equal_range_multi(key); - } - - void swap(multiset &rhs) noexcept { - tree_.swap(rhs.tree_); - } - - public: - friend bool operator==(const multiset &lhs, const multiset &rhs) { - return lhs.tree_ == rhs.tree_; - } - friend bool operator<(const multiset &lhs, const multiset &rhs) { - return lhs.tree_ < rhs.tree_; - } - }; - - // 重载比较操作符 - template - bool operator==(const multiset &lhs, - const multiset &rhs) { - return lhs == rhs; - } - - template - bool operator<(const multiset &lhs, - const multiset &rhs) { - return lhs < rhs; - } - - template - bool operator!=(const multiset &lhs, - const multiset &rhs) { - return !(lhs == rhs); - } - - template - bool operator>(const multiset &lhs, - const multiset &rhs) { - return rhs < lhs; - } - - template - bool operator<=(const multiset &lhs, - const multiset &rhs) { - return !(rhs < lhs); - } - - template - bool operator>=(const multiset &lhs, - const multiset &rhs) { - return !(lhs < rhs); - } - - // 重载 mystl 的 swap - template - void swap(multiset &lhs, - multiset &rhs) noexcept { - lhs.swap(rhs); +// 模板类 set,键值不允许重复 +// 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less +template > +class set { +public: + typedef Key key_type; + typedef Key value_type; + typedef Compare key_compare; + typedef Compare value_compare; + +private: + // 以 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; + +public: + // 使用 rb_tree 定义的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::const_pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::const_reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动函数 + set() = default; + + template + set(InputIterator first, InputIterator last) : tree_() { + tree_.insert_unique(first, last); + } + + set(std::initializer_list ilist) : tree_() { + tree_.insert_unique(ilist.begin(), ilist.end()); + } + + set(const set& rhs) : tree_(rhs.tree_) { + } + + set(set&& rhs) noexcept : tree_(mystl::move(rhs.tree_)) { + } + + set& operator=(const set& rhs) { + tree_ = rhs.tree_; + return *this; + } + + set& operator=(set&& rhs) { + tree_ = mystl::move(rhs.tree_); + return *this; + } + + set& operator=(std::initializer_list ilist) { + tree_.clear(); + tree_.insert_unique(ilist.begin(), ilist.end()); + return *this; + } + + // 相关接口 + + key_compare key_comp() const { + return tree_.key_comp(); + } + + value_compare value_comp() const { + return tree_.key_comp(); + } + + allocator_type get_allocator() const { + return tree_.get_allocator(); + } + + // 迭代器相关 + + iterator begin() noexcept { + return tree_.begin(); + } + + const_iterator begin() const noexcept { + return tree_.begin(); + } + + iterator end() noexcept { + return tree_.end(); + } + + const_iterator end() const noexcept { + return tree_.end(); + } + + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } + + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } + + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } + + const_iterator cbegin() const noexcept { + return begin(); + } + + const_iterator cend() const noexcept { + return end(); + } + + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } + + const_reverse_iterator crend() const noexcept { + return rend(); + } + + // 容量相关 + bool empty() const noexcept { + return tree_.empty(); + } + + size_type size() const noexcept { + return tree_.size(); + } + + size_type max_size() const noexcept { + return tree_.max_size(); + } + + // 插入删除操作 + + template + pair emplace(Args&&... args) { + return tree_.emplace_unique(mystl::forward(args)...); + } + + template + iterator emplace_hint(iterator hint, Args&&... args) { + return tree_.emplace_unique_use_hint(hint, + mystl::forward(args)...); + } + + pair insert(const value_type& value) { + return tree_.insert_unique(value); + } + + pair insert(value_type&& value) { + return tree_.insert_unique(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) { + return tree_.insert_unique(hint, value); + } + + iterator insert(iterator hint, value_type&& value) { + return tree_.insert_unique(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) { + tree_.insert_unique(first, last); + } + + void erase(iterator position) { + tree_.erase(position); + } + + size_type erase(const key_type& key) { + return tree_.erase_unique(key); + } + + void erase(iterator first, iterator last) { + tree_.erase(first, last); + } + + void clear() { + tree_.clear(); + } + + // set 相关操作 + + iterator find(const key_type& key) { + return tree_.find(key); + } + + const_iterator find(const key_type& key) const { + return tree_.find(key); + } + + size_type count(const key_type& key) const { + return tree_.count_unique(key); + } + + iterator lower_bound(const key_type& key) { + return tree_.lower_bound(key); + } + + const_iterator lower_bound(const key_type& key) const { + return tree_.lower_bound(key); + } + + iterator upper_bound(const key_type& key) { + return tree_.upper_bound(key); + } + + const_iterator upper_bound(const key_type& key) const { + return tree_.upper_bound(key); + } + + pair equal_range(const key_type& key) { + return tree_.equal_range_unique(key); + } + + pair + equal_range(const key_type& key) const { + return tree_.equal_range_unique(key); + } + + void swap(set& rhs) noexcept { + tree_.swap(rhs.tree_); + } + +public: + friend bool operator==(const set& lhs, const set& rhs) { + return lhs.tree_ == rhs.tree_; + } + + friend bool operator<(const set& lhs, const set& rhs) { + return lhs.tree_ < rhs.tree_; + } +}; + +// 重载比较操作符 +template +bool operator==(const set& lhs, const set& rhs) { + return lhs == rhs; +} + +template +bool operator<(const set& lhs, const set& rhs) { + return lhs < rhs; +} + +template +bool operator!=(const set& lhs, const set& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const set& lhs, const set& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const set& lhs, const set& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const set& lhs, const set& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(set& lhs, set& rhs) noexcept { + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 multiset,键值允许重复 +// 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less +template > +class multiset { +public: + typedef Key key_type; + typedef Key value_type; + typedef Compare key_compare; + typedef Compare value_compare; + +private: + // 以 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; // 以 rb_tree 表现 multiset + +public: + // 使用 rb_tree 定义的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::const_pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::const_reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动函数 + multiset() = default; + + template + multiset(InputIterator first, InputIterator last) : tree_() { + tree_.insert_multi(first, last); + } + + multiset(std::initializer_list ilist) : tree_() { + tree_.insert_multi(ilist.begin(), ilist.end()); + } + + multiset(const multiset& rhs) : tree_(rhs.tree_) { + } + + multiset(multiset&& rhs) noexcept : tree_(mystl::move(rhs.tree_)) { + } + + multiset& operator=(const multiset& rhs) { + tree_ = rhs.tree_; + return *this; + } + + multiset& operator=(multiset&& rhs) { + tree_ = mystl::move(rhs.tree_); + return *this; + } + + multiset& operator=(std::initializer_list ilist) { + tree_.clear(); + tree_.insert_multi(ilist.begin(), ilist.end()); + return *this; + } + + // 相关接口 + + key_compare key_comp() const { + return tree_.key_comp(); + } + + value_compare value_comp() const { + return tree_.key_comp(); + } + + allocator_type get_allocator() const { + return tree_.get_allocator(); + } + + // 迭代器相关 + + iterator begin() noexcept { + return tree_.begin(); + } + + const_iterator begin() const noexcept { + return tree_.begin(); + } + + iterator end() noexcept { + return tree_.end(); + } + + const_iterator end() const noexcept { + return tree_.end(); + } + + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } + + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } + + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } + + const_iterator cbegin() const noexcept { + return begin(); + } + + const_iterator cend() const noexcept { + return end(); + } + + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } + + const_reverse_iterator crend() const noexcept { + return rend(); + } + + // 容量相关 + bool empty() const noexcept { + return tree_.empty(); + } + + size_type size() const noexcept { + return tree_.size(); + } + + size_type max_size() const noexcept { + return tree_.max_size(); + } + + // 插入删除操作 + + template + iterator emplace(Args&&... args) { + return tree_.emplace_multi(mystl::forward(args)...); + } + + template + iterator emplace_hint(iterator hint, Args&&... args) { + return tree_.emplace_multi_use_hint(hint, + mystl::forward(args)...); + } + + iterator insert(const value_type& value) { + return tree_.insert_multi(value); + } + + iterator insert(value_type&& value) { + return tree_.insert_multi(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) { + return tree_.insert_multi(hint, value); + } + + iterator insert(iterator hint, value_type&& value) { + return tree_.insert_multi(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) { + tree_.insert_multi(first, last); + } + + void erase(iterator position) { + tree_.erase(position); + } + + size_type erase(const key_type& key) { + return tree_.erase_multi(key); + } + + void erase(iterator first, iterator last) { + tree_.erase(first, last); + } + + void clear() { + tree_.clear(); + } + + // multiset 相关操作 + + iterator find(const key_type& key) { + return tree_.find(key); + } + + const_iterator find(const key_type& key) const { + return tree_.find(key); + } + + size_type count(const key_type& key) const { + return tree_.count_multi(key); + } + + iterator lower_bound(const key_type& key) { + return tree_.lower_bound(key); + } + + const_iterator lower_bound(const key_type& key) const { + return tree_.lower_bound(key); + } + + iterator upper_bound(const key_type& key) { + return tree_.upper_bound(key); + } + + const_iterator upper_bound(const key_type& key) const { + return tree_.upper_bound(key); + } + + pair equal_range(const key_type& key) { + return tree_.equal_range_multi(key); + } + + pair + equal_range(const key_type& key) const { + return tree_.equal_range_multi(key); + } + + void swap(multiset& rhs) noexcept { + tree_.swap(rhs.tree_); + } + +public: + friend bool operator==(const multiset& lhs, const multiset& rhs) { + return lhs.tree_ == rhs.tree_; + } + + friend bool operator<(const multiset& lhs, const multiset& rhs) { + return lhs.tree_ < rhs.tree_; } }; -#endif /* _SET_ */ +// 重载比较操作符 +template +bool operator==(const multiset& lhs, + const multiset& rhs) { + return lhs == rhs; +} + +template +bool operator<(const multiset& lhs, + const multiset& rhs) { + return lhs < rhs; +} + +template +bool operator!=(const multiset& lhs, + const multiset& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const multiset& lhs, + const multiset& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const multiset& lhs, + const multiset& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const multiset& lhs, + const multiset& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(multiset& lhs, multiset& rhs) noexcept { + lhs.swap(rhs); +} +}; // namespace mystl + +#endif /* SIMPLEKERNEL_SET */ diff --git a/src/libcxx/include/set_algo b/src/libcxx/include/set_algo index b3b3753d7..951e552ed 100644 --- a/src/libcxx/include/set_algo +++ b/src/libcxx/include/set_algo @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// set_algo for Simple-XX/SimpleKernel. +/** + * @file set_algo + * @brief stl set_algo 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ -#ifndef _SET_ALGO_ -#define _SET_ALGO_ +#ifndef SIMPLEKERNEL_SET_ALGO +#define SIMPLEKERNEL_SET_ALGO // 这个头文件包含 set 的四种算法: union, intersection, difference, // symmetric_difference 所有函数都要求序列有序 @@ -15,207 +26,203 @@ namespace mystl { - /*****************************************************************************************/ - // set_union - // 计算 S1∪S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 - /*****************************************************************************************/ - template - OutputIter set_union(InputIter1 first1, InputIter1 last1, InputIter2 first2, - InputIter2 last2, OutputIter result) { - while (first1 != last1 && first2 != last2) { - if (*first1 < *first2) { - *result = *first1; - ++first1; - } - else if (*first2 < *first1) { - *result = *first2; - ++first2; - } - else { - *result = *first1; - ++first1; - ++first2; - } - ++result; +/*****************************************************************************************/ +// set_union +// 计算 S1∪S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter set_union(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result) { + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + *result = *first1; + ++first1; + } + else if (*first2 < *first1) { + *result = *first2; + ++first2; } - // 将剩余元素拷贝到 result - return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); + else { + *result = *first1; + ++first1; + ++first2; + } + ++result; } + // 将剩余元素拷贝到 result + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} - // 重载版本使用函数对象 comp 代替比较操作 - template - OutputIter set_union(InputIter1 first1, InputIter1 last1, InputIter2 first2, - InputIter2 last2, OutputIter result, Compared comp) { - while (first1 != last1 && first2 != last2) { - if (comp(*first1, *first2)) { - *result = *first1; - ++first1; - } - else if (comp(*first2, *first1)) { - *result = *first2; - ++first2; - } - else { - *result = *first1; - ++first1; - ++first2; - } - ++result; +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter set_union(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result, Compared comp) { + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + *result = *first1; + ++first1; + } + else if (comp(*first2, *first1)) { + *result = *first2; + ++first2; } - // 将剩余元素拷贝到 result - return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); + else { + *result = *first1; + ++first1; + ++first2; + } + ++result; } + // 将剩余元素拷贝到 result + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} - /*****************************************************************************************/ - // set_intersection - // 计算 S1∩S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 - /*****************************************************************************************/ - template - OutputIter set_intersection(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - OutputIter result) { - while (first1 != last1 && first2 != last2) { - if (*first1 < *first2) { - ++first1; - } - else if (*first2 < *first1) { - ++first2; - } - else { - *result = *first1; - ++first1; - ++first2; - ++result; - } - } - return result; +/*****************************************************************************************/ +// set_intersection +// 计算 S1∩S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter +set_intersection(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result) { + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + ++first1; + } + else if (*first2 < *first1) { + ++first2; + } + else { + *result = *first1; + ++first1; + ++first2; + ++result; + } } + return result; +} - // 重载版本使用函数对象 comp 代替比较操作 - template - OutputIter set_intersection(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - OutputIter result, Compared comp) { - while (first1 != last1 && first2 != last2) { - if (comp(*first1, *first2)) { - ++first1; - } - else if (comp(*first2, *first1)) { - ++first2; - } - else { - *result = *first1; - ++first1; - ++first2; - ++result; - } - } - return result; +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter +set_intersection(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result, Compared comp) { + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + ++first1; + } + else if (comp(*first2, *first1)) { + ++first2; + } + else { + *result = *first1; + ++first1; + ++first2; + ++result; + } } + return result; +} - /*****************************************************************************************/ - // set_difference - // 计算 S1-S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 - /*****************************************************************************************/ - template - OutputIter set_difference(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - OutputIter result) { - while (first1 != last1 && first2 != last2) { - if (*first1 < *first2) { - *result = *first1; - ++first1; - ++result; - } - else if (*first2 < *first1) { - ++first2; - } - else { - ++first1; - ++first2; - } - } - return mystl::copy(first1, last1, result); +/*****************************************************************************************/ +// set_difference +// 计算 S1-S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter +set_difference(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result) { + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + *result = *first1; + ++first1; + ++result; + } + else if (*first2 < *first1) { + ++first2; + } + else { + ++first1; + ++first2; + } } + return mystl::copy(first1, last1, result); +} - // 重载版本使用函数对象 comp 代替比较操作 - template - OutputIter set_difference(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - OutputIter result, Compared comp) { - while (first1 != last1 && first2 != last2) { - if (comp(*first1, *first2)) { - *result = *first1; - ++first1; - ++result; - } - else if (comp(*first2, *first1)) { - ++first2; - } - else { - ++first1; - ++first2; - } - } - return mystl::copy(first1, last1, result); +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter +set_difference(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result, Compared comp) { + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + *result = *first1; + ++first1; + ++result; + } + else if (comp(*first2, *first1)) { + ++first2; + } + else { + ++first1; + ++first2; + } } + return mystl::copy(first1, last1, result); +} - /*****************************************************************************************/ - // set_symmetric_difference - // 计算 (S1-S2)∪(S2-S1) 的结果并保存到 result - // 中,返回一个迭代器指向输出结果的尾部 - /*****************************************************************************************/ - template - OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - OutputIter result) { - while (first1 != last1 && first2 != last2) { - if (*first1 < *first2) { - *result = *first1; - ++first1; - ++result; - } - else if (*first2 < *first1) { - *result = *first2; - ++first2; - ++result; - } - else { - ++first1; - ++first2; - } - } - return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +/*****************************************************************************************/ +// set_symmetric_difference +// 计算 (S1-S2)∪(S2-S1) 的结果并保存到 result +// 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter +set_symmetric_difference(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result) { + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + *result = *first1; + ++first1; + ++result; + } + else if (*first2 < *first1) { + *result = *first2; + ++first2; + ++result; + } + else { + ++first1; + ++first2; + } } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} - // 重载版本使用函数对象 comp 代替比较操作 - template - OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1, - InputIter2 first2, InputIter2 last2, - OutputIter result, Compared comp) { - while (first1 != last1 && first2 != last2) { - if (comp(*first1, *first2)) { - *result = *first1; - ++first1; - ++result; - } - else if (comp(*first2, *first1)) { - *result = *first2; - ++first2; - ++result; - } - else { - ++first1; - ++first2; - } - } - return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter +set_symmetric_difference(InputIter1 first1, InputIter1 last1, InputIter2 first2, + InputIter2 last2, OutputIter result, Compared comp) { + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + *result = *first1; + ++first1; + ++result; + } + else if (comp(*first2, *first1)) { + *result = *first2; + ++first2; + ++result; + } + else { + ++first1; + ++first2; + } } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} -}; +}; // namespace mystl -#endif /* _SET_ALGO_ */ +#endif /* SIMPLEKERNEL_SET_ALGO */ diff --git a/src/libcxx/include/stack b/src/libcxx/include/stack index 1b7bdb829..bef748062 100644 --- a/src/libcxx/include/stack +++ b/src/libcxx/include/stack @@ -1,179 +1,199 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// stack for Simple-XX/SimpleKernel. - -#ifndef _STACK_ -#define _STACK_ +/** + * @file stack + * @brief stl stack 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_STACK +#define SIMPLEKERNEL_STACK // 这个头文件包含了一个模板类 stack // stack : 栈 #include "deque" -namespace mystl -{ +namespace mystl { // 模板类 stack -// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器 +// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque +// 作为底层容器 template > -class stack -{ +class stack { public: - typedef Container container_type; - // 使用底层容器的型别 - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - - static_assert(std::is_same::value, - "the value_type of Container should be same with T"); + typedef Container container_type; + // 使用底层容器的型别 + typedef typename Container::value_type value_type; + typedef typename Container::size_type size_type; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; + + static_assert(std::is_same::value, + "the value_type of Container should be same with T"); + private: - container_type c_; // 用底层容器表现 stack + container_type c_; // 用底层容器表现 stack public: - // 构造、复制、移动函数 - stack() = default; - - explicit stack(size_type n) - :c_(n) - { - } - stack(size_type n, const value_type& value) - :c_(n, value) - { - } - - template - stack(IIter first, IIter last) - : c_(first, last) - { - } - - stack(std::initializer_list ilist) - :c_(ilist.begin(), ilist.end()) - { - } - - stack(const Container& c) - :c_(c) - { - } - stack(Container&& c) noexcept(std::is_nothrow_move_constructible::value) - :c_(mystl::move(c)) - { - } - - stack(const stack& rhs) - :c_(rhs.c_) - { - } - stack(stack&& rhs) noexcept(std::is_nothrow_move_constructible::value) - :c_(mystl::move(rhs.c_)) - { - } - - stack& operator=(const stack& rhs) - { - c_ = rhs.c_; - return *this; - } - stack& operator=(stack&& rhs) noexcept(std::is_nothrow_move_assignable::value) - { - c_ = mystl::move(rhs.c_); - return *this; - } - - stack& operator=(std::initializer_list ilist) - { - c_ = ilist; - return *this; - } - - ~stack() = default; - - // 访问元素相关操作 - reference top() { return c_.back(); } - const_reference top() const { return c_.back(); } - - // 容量相关操作 - bool empty() const noexcept { return c_.empty(); } - size_type size() const noexcept { return c_.size(); } - - // 修改容器相关操作 - - template - void emplace(Args&& ...args) - { c_.emplace_back(mystl::forward(args)...); } - - void push(const value_type& value) - { c_.push_back(value); } - void push(value_type&& value) - { c_.push_back(mystl::move(value)); } - - void pop() - { c_.pop_back(); } - - void clear() - { - while (!empty()) - pop(); - } - - void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) - { mystl::swap(c_, rhs.c_); } + // 构造、复制、移动函数 + stack() = default; + + explicit stack(size_type n) : c_(n) { + } + + stack(size_type n, const value_type& value) : c_(n, value) { + } + + template + stack(IIter first, IIter last) : c_(first, last) { + } + + stack(std::initializer_list ilist) : c_(ilist.begin(), ilist.end()) { + } + + stack(const Container& c) : c_(c) { + } + + stack(Container&& c) noexcept( + std::is_nothrow_move_constructible::value) + : c_(mystl::move(c)) { + } + + stack(const stack& rhs) : c_(rhs.c_) { + } + + stack(stack&& rhs) noexcept( + std::is_nothrow_move_constructible::value) + : c_(mystl::move(rhs.c_)) { + } + + stack& operator=(const stack& rhs) { + c_ = rhs.c_; + return *this; + } + + stack& operator=(stack&& rhs) noexcept( + std::is_nothrow_move_assignable::value) { + c_ = mystl::move(rhs.c_); + return *this; + } + + stack& operator=(std::initializer_list ilist) { + c_ = ilist; + return *this; + } + + ~stack() = default; + + // 访问元素相关操作 + reference top() { + return c_.back(); + } + + const_reference top() const { + return c_.back(); + } + + // 容量相关操作 + bool empty() const noexcept { + return c_.empty(); + } + + size_type size() const noexcept { + return c_.size(); + } + + // 修改容器相关操作 + + template + void emplace(Args&&... args) { + c_.emplace_back(mystl::forward(args)...); + } + + void push(const value_type& value) { + c_.push_back(value); + } + + void push(value_type&& value) { + c_.push_back(mystl::move(value)); + } + + void pop() { + c_.pop_back(); + } + + void clear() { + while (!empty()) { + pop(); + } + } + + void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) { + mystl::swap(c_, rhs.c_); + } public: - friend bool operator==(const stack& lhs, const stack& rhs) { return lhs.c_ == rhs.c_; } - friend bool operator< (const stack& lhs, const stack& rhs) { return lhs.c_ < rhs.c_; } + friend bool operator==(const stack& lhs, const stack& rhs) { + return lhs.c_ == rhs.c_; + } + + friend bool operator<(const stack& lhs, const stack& rhs) { + return lhs.c_ < rhs.c_; + } }; // 重载比较操作符 template -bool operator==(const stack& lhs, const stack& rhs) -{ - return lhs == rhs; +bool operator==(const stack& lhs, + const stack& rhs) { + return lhs == rhs; } template -bool operator<(const stack& lhs, const stack& rhs) -{ - return lhs < rhs; +bool operator<(const stack& lhs, const stack& rhs) { + return lhs < rhs; } template -bool operator!=(const stack& lhs, const stack& rhs) -{ - return !(lhs == rhs); +bool operator!=(const stack& lhs, + const stack& rhs) { + return !(lhs == rhs); } template -bool operator>(const stack& lhs, const stack& rhs) -{ - return rhs < lhs; +bool operator>(const stack& lhs, const stack& rhs) { + return rhs < lhs; } template -bool operator<=(const stack& lhs, const stack& rhs) -{ - return !(rhs < lhs); +bool operator<=(const stack& lhs, + const stack& rhs) { + return !(rhs < lhs); } template -bool operator>=(const stack& lhs, const stack& rhs) -{ - return !(lhs < rhs); +bool operator>=(const stack& lhs, + const stack& rhs) { + return !(lhs < rhs); } // 重载 mystl 的 swap template -void swap(stack& lhs, stack& rhs) noexcept(noexcept(lhs.swap(rhs))) -{ - lhs.swap(rhs); +void swap(stack& lhs, + stack& rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); } -}; +}; // namespace mystl -#endif /* _STACK_ */ +#endif /* SIMPLEKERNEL_STACK */ diff --git a/src/libcxx/include/string b/src/libcxx/include/string index 769d391d1..dc32effca 100644 --- a/src/libcxx/include/string +++ b/src/libcxx/include/string @@ -1,12 +1,23 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/zouxiaohang/TinySTL -// string for Simple-XX/SimpleKernel. +/** + * @file string + * @brief stl string 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ -#ifndef _STRING_ -#define _STRING_ +#ifndef SIMPLEKERNEL_STRING +#define SIMPLEKERNEL_STRING #include "astring" -#endif /* _STRING_ */ +#endif /* SIMPLEKERNEL_STRING */ diff --git a/src/libcxx/include/type_traits b/src/libcxx/include/type_traits index 48e616865..1dd441ddd 100644 --- a/src/libcxx/include/type_traits +++ b/src/libcxx/include/type_traits @@ -1,2959 +1,2951 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/gcc-mirror/gcc -// type_traits for Simple-XX/SimpleKernel. +/** + * @file type_traits + * @brief stl type_traits 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_TYPE_TRAITS +#define SIMPLEKERNEL_TYPE_TRAITS -#ifndef _TYPE_TRAITS_ -#define _TYPE_TRAITS_ - -#include "stdint.h" #include "stddef.h" +#include "stdint.h" namespace std { - typedef decltype(nullptr) nullptr_t; +typedef decltype(nullptr) nullptr_t; #define _GLIBCXX20_DEPRECATED(MSG) [[deprecated(MSG)]] - /** - * @defgroup metaprogramming Metaprogramming - * @ingroup utilities - * - * Template utilities for compile-time introspection and modification, - * including type classification traits, type property inspection traits - * and type transformation traits. - * - * @{ - */ - - /// integral_constant - template - struct integral_constant { - static constexpr _Tp value = __v; - typedef _Tp value_type; - typedef integral_constant<_Tp, __v> type; - constexpr operator value_type() const noexcept { - return value; - } +/** + * @defgroup metaprogramming Metaprogramming + * @ingroup utilities + * + * Template utilities for compile-time introspection and modification, + * including type classification traits, type property inspection traits + * and type transformation traits. + * + * @{ + */ + +/// integral_constant +template +struct integral_constant { + static constexpr _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant<_Tp, __v> type; + + constexpr operator value_type() const noexcept { + return value; + } #if __cplusplus > 201103L -#define __cpp_lib_integral_constant_callable 201304 +# define __cpp_lib_integral_constant_callable 201304 - constexpr value_type operator()() const noexcept { - return value; - } + constexpr value_type operator()() const noexcept { + return value; + } #endif - }; +}; - template - constexpr _Tp integral_constant<_Tp, __v>::value; +template +constexpr _Tp integral_constant<_Tp, __v>::value; - /// The type used as a compile-time boolean with true value. - typedef integral_constant true_type; +/// The type used as a compile-time boolean with true value. +typedef integral_constant true_type; - /// The type used as a compile-time boolean with false value. - typedef integral_constant false_type; +/// The type used as a compile-time boolean with false value. +typedef integral_constant false_type; - template - using __bool_constant = integral_constant; +template +using __bool_constant = integral_constant; #if __cplusplus > 201402L -#define __cpp_lib_bool_constant 201505 - template - using bool_constant = integral_constant; +# define __cpp_lib_bool_constant 201505 +template +using bool_constant = integral_constant; #endif - // Meta programming helper types. +// Meta programming helper types. - template - struct conditional; +template +struct conditional; - template - struct __type_identity { - using type = _Type; - }; +template +struct __type_identity { + using type = _Type; +}; - template - using __type_identity_t = typename __type_identity<_Tp>::type; +template +using __type_identity_t = typename __type_identity<_Tp>::type; - template - struct __or_; +template +struct __or_; - template <> - struct __or_<> : public false_type {}; +template <> +struct __or_<> : public false_type { }; - template - struct __or_<_B1> : public _B1 {}; +template +struct __or_<_B1> : public _B1 { }; - template - struct __or_<_B1, _B2> : public conditional<_B1::value, _B1, _B2>::type {}; +template +struct __or_<_B1, _B2> : public conditional<_B1::value, _B1, _B2>::type { }; - template - struct __or_<_B1, _B2, _B3, _Bn...> - : public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type {}; +template +struct __or_<_B1, _B2, _B3, _Bn...> + : public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type { }; - template - struct __and_; +template +struct __and_; - template <> - struct __and_<> : public true_type {}; +template <> +struct __and_<> : public true_type { }; - template - struct __and_<_B1> : public _B1 {}; +template +struct __and_<_B1> : public _B1 { }; - template - struct __and_<_B1, _B2> : public conditional<_B1::value, _B2, _B1>::type {}; +template +struct __and_<_B1, _B2> : public conditional<_B1::value, _B2, _B1>::type { }; - template - struct __and_<_B1, _B2, _B3, _Bn...> - : public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, _B1>::type { - }; +template +struct __and_<_B1, _B2, _B3, _Bn...> + : public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, _B1>::type { }; - template - struct __not_ : public __bool_constant {}; +template +struct __not_ : public __bool_constant { }; #if __cplusplus >= 201703L - template - inline constexpr bool __or_v = __or_<_Bn...>::value; - template - inline constexpr bool __and_v = __and_<_Bn...>::value; +template +inline constexpr bool __or_v = __or_<_Bn...>::value; +template +inline constexpr bool __and_v = __and_<_Bn...>::value; -#define __cpp_lib_logical_traits 201510 +# define __cpp_lib_logical_traits 201510 - template - struct conjunction : __and_<_Bn...> {}; +template +struct conjunction : __and_<_Bn...> { }; - template - struct disjunction : __or_<_Bn...> {}; +template +struct disjunction : __or_<_Bn...> { }; - template - struct negation : __not_<_Pp> {}; +template +struct negation : __not_<_Pp> { }; - template - inline constexpr bool conjunction_v = conjunction<_Bn...>::value; +template +inline constexpr bool conjunction_v = conjunction<_Bn...>::value; - template - inline constexpr bool disjunction_v = disjunction<_Bn...>::value; +template +inline constexpr bool disjunction_v = disjunction<_Bn...>::value; - template - inline constexpr bool negation_v = negation<_Pp>::value; +template +inline constexpr bool negation_v = negation<_Pp>::value; -#endif // C++17 +#endif // C++17 - // Forward declarations - template - struct is_reference; - template - struct is_function; - template - struct is_void; - template - struct __is_array_unknown_bounds; +// Forward declarations +template +struct is_reference; +template +struct is_function; +template +struct is_void; +template +struct __is_array_unknown_bounds; - // Helper functions that return false_type for incomplete classes, - // incomplete unions and arrays of known bound from those. +// Helper functions that return false_type for incomplete classes, +// incomplete unions and arrays of known bound from those. - template - constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>) { - return {}; - } +template +constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>) { + return {}; +} - template - constexpr typename __or_, - is_function<_NestedType>, is_void<_NestedType>, - __is_array_unknown_bounds<_NestedType>>::type - __is_complete_or_unbounded(_TypeIdentity) { - return {}; - } +template +constexpr typename __or_, is_function<_NestedType>, + is_void<_NestedType>, + __is_array_unknown_bounds<_NestedType>>::type +__is_complete_or_unbounded(_TypeIdentity) { + return {}; +} - // For several sfinae-friendly trait implementations we transport both the - // result information (as the member type) and the failure information (no - // member type). This is very similar to std::enable_if, but we cannot use - // them, because we need to derive from them as an implementation detail. +// For several sfinae-friendly trait implementations we transport both the +// result information (as the member type) and the failure information (no +// member type). This is very similar to std::enable_if, but we cannot use +// them, because we need to derive from them as an implementation detail. - template - struct __success_type { - typedef _Tp type; - }; +template +struct __success_type { + typedef _Tp type; +}; - struct __failure_type {}; +struct __failure_type { }; - template - struct remove_cv; +template +struct remove_cv; - // __remove_cv_t (std::remove_cv_t for C++11). - template - using __remove_cv_t = typename remove_cv<_Tp>::type; +// __remove_cv_t (std::remove_cv_t for C++11). +template +using __remove_cv_t = typename remove_cv<_Tp>::type; - template - struct is_const; +template +struct is_const; - // Primary type categories. +// Primary type categories. - template - struct __is_void_helper : public false_type {}; +template +struct __is_void_helper : public false_type { }; - template <> - struct __is_void_helper : public true_type {}; +template <> +struct __is_void_helper : public true_type { }; - /// is_void - template - struct is_void : public __is_void_helper<__remove_cv_t<_Tp>>::type {}; +/// is_void +template +struct is_void : public __is_void_helper<__remove_cv_t<_Tp>>::type { }; - template - struct __is_integral_helper : public false_type {}; +template +struct __is_integral_helper : public false_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; #ifdef _GLIBCXX_USE_WCHAR_T - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; #endif #ifdef _GLIBCXX_USE_CHAR8_T - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; #endif - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - template <> - struct __is_integral_helper : public true_type {}; +template <> +struct __is_integral_helper : public true_type { }; - // Conditionalizing on __STRICT_ANSI__ here will break any port that - // uses one of these types for size_t. +// Conditionalizing on __STRICT_ANSI__ here will break any port that +// uses one of these types for size_t. #if defined(__GLIBCXX_TYPE_INT_N_0) - template <> - struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0> : public true_type {}; +template <> +struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0> : public true_type { }; - template <> - struct __is_integral_helper - : public true_type {}; +template <> +struct __is_integral_helper + : public true_type { }; #endif #if defined(__GLIBCXX_TYPE_INT_N_1) - template <> - struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1> : public true_type {}; +template <> +struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1> : public true_type { }; - template <> - struct __is_integral_helper - : public true_type {}; +template <> +struct __is_integral_helper + : public true_type { }; #endif #if defined(__GLIBCXX_TYPE_INT_N_2) - template <> - struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2> : public true_type {}; +template <> +struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2> : public true_type { }; - template <> - struct __is_integral_helper - : public true_type {}; +template <> +struct __is_integral_helper + : public true_type { }; #endif #if defined(__GLIBCXX_TYPE_INT_N_3) - template <> - struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3> : public true_type {}; +template <> +struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3> : public true_type { }; - template <> - struct __is_integral_helper - : public true_type {}; +template <> +struct __is_integral_helper + : public true_type { }; #endif - /// is_integral - template - struct is_integral : public __is_integral_helper<__remove_cv_t<_Tp>>::type { - }; +/// is_integral +template +struct is_integral : public __is_integral_helper<__remove_cv_t<_Tp>>::type { }; - template - struct __is_floating_point_helper : public false_type {}; +template +struct __is_floating_point_helper : public false_type { }; - template <> - struct __is_floating_point_helper : public true_type {}; +template <> +struct __is_floating_point_helper : public true_type { }; - template <> - struct __is_floating_point_helper : public true_type {}; +template <> +struct __is_floating_point_helper : public true_type { }; - template <> - struct __is_floating_point_helper : public true_type {}; +template <> +struct __is_floating_point_helper : public true_type { }; #if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) - template <> - struct __is_floating_point_helper<__float128> : public true_type {}; +template <> +struct __is_floating_point_helper<__float128> : public true_type { }; #endif - /// is_floating_point - template - struct is_floating_point - : public __is_floating_point_helper<__remove_cv_t<_Tp>>::type {}; +/// is_floating_point +template +struct is_floating_point + : public __is_floating_point_helper<__remove_cv_t<_Tp>>::type { }; - /// is_array - template - struct is_array : public false_type {}; +/// is_array +template +struct is_array : public false_type { }; - template - struct is_array<_Tp[_Size]> : public true_type {}; +template +struct is_array<_Tp[_Size]> : public true_type { }; - template - struct is_array<_Tp[]> : public true_type {}; +template +struct is_array<_Tp[]> : public true_type { }; - template - struct __is_pointer_helper : public false_type {}; +template +struct __is_pointer_helper : public false_type { }; - template - struct __is_pointer_helper<_Tp *> : public true_type {}; +template +struct __is_pointer_helper<_Tp*> : public true_type { }; - /// is_pointer - template - struct is_pointer : public __is_pointer_helper<__remove_cv_t<_Tp>>::type {}; +/// is_pointer +template +struct is_pointer : public __is_pointer_helper<__remove_cv_t<_Tp>>::type { }; - /// is_lvalue_reference - template - struct is_lvalue_reference : public false_type {}; +/// is_lvalue_reference +template +struct is_lvalue_reference : public false_type { }; - template - struct is_lvalue_reference<_Tp &> : public true_type {}; +template +struct is_lvalue_reference<_Tp&> : public true_type { }; - /// is_rvalue_reference - template - struct is_rvalue_reference : public false_type {}; +/// is_rvalue_reference +template +struct is_rvalue_reference : public false_type { }; - template - struct is_rvalue_reference<_Tp &&> : public true_type {}; +template +struct is_rvalue_reference<_Tp&&> : public true_type { }; - template - struct __is_member_object_pointer_helper : public false_type {}; +template +struct __is_member_object_pointer_helper : public false_type { }; - template - struct __is_member_object_pointer_helper<_Tp _Cp::*> - : public __not_>::type {}; +template +struct __is_member_object_pointer_helper<_Tp _Cp::*> + : public __not_>::type { }; - /// is_member_object_pointer - template - struct is_member_object_pointer - : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type {}; +/// is_member_object_pointer +template +struct is_member_object_pointer + : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type { }; - template - struct __is_member_function_pointer_helper : public false_type {}; +template +struct __is_member_function_pointer_helper : public false_type { }; - template - struct __is_member_function_pointer_helper<_Tp _Cp::*> - : public is_function<_Tp>::type {}; +template +struct __is_member_function_pointer_helper<_Tp _Cp::*> + : public is_function<_Tp>::type { }; - /// is_member_function_pointer - template - struct is_member_function_pointer - : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type { - }; +/// is_member_function_pointer +template +struct is_member_function_pointer + : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type { }; - /// is_enum - template - struct is_enum : public integral_constant {}; +/// is_enum +template +struct is_enum : public integral_constant { }; - /// is_union - template - struct is_union : public integral_constant {}; +/// is_union +template +struct is_union : public integral_constant { }; - /// is_class - template - struct is_class : public integral_constant {}; +/// is_class +template +struct is_class : public integral_constant { }; - /// is_function - template - struct is_function : public __bool_constant::value> {}; +/// is_function +template +struct is_function : public __bool_constant::value> { }; - template - struct is_function<_Tp &> : public false_type {}; +template +struct is_function<_Tp&> : public false_type { }; - template - struct is_function<_Tp &&> : public false_type {}; +template +struct is_function<_Tp&&> : public false_type { }; #define __cpp_lib_is_null_pointer 201309 - template - struct __is_null_pointer_helper : public false_type {}; - - template <> - struct __is_null_pointer_helper : public true_type {}; - - /// is_null_pointer (LWG 2247). - template - struct is_null_pointer - : public __is_null_pointer_helper<__remove_cv_t<_Tp>>::type {}; - - /// __is_nullptr_t (deprecated extension). - template - struct __is_nullptr_t : public is_null_pointer<_Tp> { - } __attribute__((__deprecated__)); - - // Composite type categories. - - /// is_reference - template - struct is_reference : public __or_, - is_rvalue_reference<_Tp>>::type {}; - - /// is_arithmetic - template - struct is_arithmetic - : public __or_, is_floating_point<_Tp>>::type {}; - - /// is_fundamental - template - struct is_fundamental : public __or_, is_void<_Tp>, - is_null_pointer<_Tp>>::type {}; - - /// is_object - template - struct is_object - : public __not_< - __or_, is_reference<_Tp>, is_void<_Tp>>>::type { - }; - - template - struct is_member_pointer; - - /// is_scalar - template - struct is_scalar - : public __or_, is_enum<_Tp>, is_pointer<_Tp>, - is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type {}; - - /// is_compound - template - struct is_compound : public __not_>::type {}; - - template - struct __is_member_pointer_helper : public false_type {}; - - template - struct __is_member_pointer_helper<_Tp _Cp::*> : public true_type {}; - - /// is_member_pointer - template - struct is_member_pointer - : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type {}; - - template - struct is_same; - - template - using __is_one_of = __or_...>; - - // Check if a type is one of the signed integer types. - template - using __is_signed_integer = - __is_one_of<__remove_cv_t<_Tp>, signed char, signed short, signed int, - signed long, signed long long +template +struct __is_null_pointer_helper : public false_type { }; + +template <> +struct __is_null_pointer_helper : public true_type { }; + +/// is_null_pointer (LWG 2247). +template +struct is_null_pointer + : public __is_null_pointer_helper<__remove_cv_t<_Tp>>::type { }; + +/// __is_nullptr_t (deprecated extension). +template +struct __is_nullptr_t : public is_null_pointer<_Tp> { +} __attribute__((__deprecated__)); + +// Composite type categories. + +/// is_reference +template +struct is_reference + : public __or_, is_rvalue_reference<_Tp>>::type { +}; + +/// is_arithmetic +template +struct is_arithmetic + : public __or_, is_floating_point<_Tp>>::type { }; + +/// is_fundamental +template +struct is_fundamental : public __or_, is_void<_Tp>, + is_null_pointer<_Tp>>::type { }; + +/// is_object +template +struct is_object + : public __not_< + __or_, is_reference<_Tp>, is_void<_Tp>>>::type { }; + +template +struct is_member_pointer; + +/// is_scalar +template +struct is_scalar + : public __or_, is_enum<_Tp>, is_pointer<_Tp>, + is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type { }; + +/// is_compound +template +struct is_compound : public __not_>::type { }; + +template +struct __is_member_pointer_helper : public false_type { }; + +template +struct __is_member_pointer_helper<_Tp _Cp::*> : public true_type { }; + +/// is_member_pointer +template +struct is_member_pointer + : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type { }; + +template +struct is_same; + +template +using __is_one_of = __or_...>; + +// Check if a type is one of the signed integer types. +template +using __is_signed_integer + = __is_one_of<__remove_cv_t<_Tp>, signed char, signed short, signed int, + signed long, signed long long #if defined(__GLIBCXX_TYPE_INT_N_0) - , - signed __GLIBCXX_TYPE_INT_N_0 + , + signed __GLIBCXX_TYPE_INT_N_0 #endif #if defined(__GLIBCXX_TYPE_INT_N_1) - , - signed __GLIBCXX_TYPE_INT_N_1 + , + signed __GLIBCXX_TYPE_INT_N_1 #endif #if defined(__GLIBCXX_TYPE_INT_N_2) - , - signed __GLIBCXX_TYPE_INT_N_2 + , + signed __GLIBCXX_TYPE_INT_N_2 #endif #if defined(__GLIBCXX_TYPE_INT_N_3) - , - signed __GLIBCXX_TYPE_INT_N_3 + , + signed __GLIBCXX_TYPE_INT_N_3 #endif - >; + >; - // Check if a type is one of the unsigned integer types. - template - using __is_unsigned_integer = - __is_one_of<__remove_cv_t<_Tp>, unsigned char, unsigned short, - unsigned int, unsigned long, unsigned long long +// Check if a type is one of the unsigned integer types. +template +using __is_unsigned_integer + = __is_one_of<__remove_cv_t<_Tp>, unsigned char, unsigned short, unsigned int, + unsigned long, unsigned long long #if defined(__GLIBCXX_TYPE_INT_N_0) - , - unsigned __GLIBCXX_TYPE_INT_N_0 + , + unsigned __GLIBCXX_TYPE_INT_N_0 #endif #if defined(__GLIBCXX_TYPE_INT_N_1) - , - unsigned __GLIBCXX_TYPE_INT_N_1 + , + unsigned __GLIBCXX_TYPE_INT_N_1 #endif #if defined(__GLIBCXX_TYPE_INT_N_2) - , - unsigned __GLIBCXX_TYPE_INT_N_2 + , + unsigned __GLIBCXX_TYPE_INT_N_2 #endif #if defined(__GLIBCXX_TYPE_INT_N_3) - , - unsigned __GLIBCXX_TYPE_INT_N_3 + , + unsigned __GLIBCXX_TYPE_INT_N_3 #endif - >; + >; + +// Check if a type is one of the signed or unsigned integer types. +template +using __is_standard_integer + = __or_<__is_signed_integer<_Tp>, __is_unsigned_integer<_Tp>>; + +// __void_t (std::void_t for C++11) +template +using __void_t = void; + +// Utility to detect referenceable types ([defns.referenceable]). + +template +struct __is_referenceable : public false_type {}; + +template +struct __is_referenceable<_Tp, __void_t<_Tp&>> : public true_type {}; + +// Type properties. + +/// is_const +template +struct is_const : public false_type { }; + +template +struct is_const : public true_type { }; + +/// is_volatile +template +struct is_volatile : public false_type { }; + +template +struct is_volatile : public true_type { }; + +/// is_trivial +template +struct is_trivial : public integral_constant { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +// is_trivially_copyable +template +struct is_trivially_copyable + : public integral_constant { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_standard_layout +template +struct is_standard_layout + : public integral_constant { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_pod (deprecated in C++20) +// Could use is_standard_layout && is_trivial instead of the builtin. +template +struct _GLIBCXX20_DEPRECATED("use is_standard_layout && is_trivial instead") + is_pod : public integral_constant { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_literal_type +template +struct is_literal_type + : public integral_constant { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_empty +template +struct is_empty : public integral_constant { }; + +/// is_polymorphic +template +struct is_polymorphic : public integral_constant { +}; - // Check if a type is one of the signed or unsigned integer types. - template - using __is_standard_integer = - __or_<__is_signed_integer<_Tp>, __is_unsigned_integer<_Tp>>; - - // __void_t (std::void_t for C++11) - template - using __void_t = void; +#if __cplusplus >= 201402L +# define __cpp_lib_is_final 201402L - // Utility to detect referenceable types ([defns.referenceable]). +/// is_final +template +struct is_final : public integral_constant { }; +#endif - template - struct __is_referenceable : public false_type {}; +/// is_abstract +template +struct is_abstract : public integral_constant { }; - template - struct __is_referenceable<_Tp, __void_t<_Tp &>> : public true_type {}; +template ::value> +struct __is_signed_helper : public false_type { }; - // Type properties. +template +struct __is_signed_helper<_Tp, true> + : public integral_constant { }; - /// is_const - template - struct is_const : public false_type {}; +/// is_signed +template +struct is_signed : public __is_signed_helper<_Tp>::type { }; - template - struct is_const<_Tp const> : public true_type {}; +/// is_unsigned +template +struct is_unsigned : public __and_, __not_>> { +}; - /// is_volatile - template - struct is_volatile : public false_type {}; +// Destructible and constructible type properties. - template - struct is_volatile<_Tp volatile> : public true_type {}; +/** + * @brief Utility to simplify expressions used in unevaluated operands + * @ingroup utilities + */ - /// is_trivial - template - struct is_trivial : public integral_constant { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +_Up __declval(int); - // is_trivially_copyable - template - struct is_trivially_copyable - : public integral_constant { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +_Tp __declval(long); - /// is_standard_layout - template - struct is_standard_layout - : public integral_constant { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +auto declval() noexcept -> decltype(__declval<_Tp>(0)); - /// is_pod (deprecated in C++20) - // Could use is_standard_layout && is_trivial instead of the builtin. - template - struct _GLIBCXX20_DEPRECATED("use is_standard_layout && is_trivial instead") - is_pod : public integral_constant { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +struct extent; - /// is_literal_type - template - struct is_literal_type - : public integral_constant { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +struct remove_all_extents; - /// is_empty - template - struct is_empty : public integral_constant {}; +template +struct __is_array_known_bounds + : public integral_constant::value > 0)> { }; - /// is_polymorphic - template - struct is_polymorphic - : public integral_constant {}; +template +struct __is_array_unknown_bounds + : public __and_, __not_>> { }; -#if __cplusplus >= 201402L -#define __cpp_lib_is_final 201402L - /// is_final - template - struct is_final : public integral_constant {}; -#endif +// In N3290 is_destructible does not say anything about function +// types and abstract types, see LWG 2049. This implementation +// describes function types as non-destructible and all complete +// object types as destructible, iff the explicit destructor +// call expression is wellformed. +struct __do_is_destructible_impl { + template ().~_Tp())> + static true_type __test(int); - /// is_abstract - template - struct is_abstract : public integral_constant {}; + template + static false_type __test(...); +}; + +template +struct __is_destructible_impl : public __do_is_destructible_impl { + typedef decltype(__test<_Tp>(0)) type; +}; + +template , __is_array_unknown_bounds<_Tp>, + is_function<_Tp>>::value, + bool = __or_, is_scalar<_Tp>>::value> +struct __is_destructible_safe; + +template +struct __is_destructible_safe<_Tp, false, false> + : public __is_destructible_impl< + typename remove_all_extents<_Tp>::type>::type { }; + +template +struct __is_destructible_safe<_Tp, true, false> : public false_type { }; + +template +struct __is_destructible_safe<_Tp, false, true> : public true_type { }; + +/// is_destructible +template +struct is_destructible : public __is_destructible_safe<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +// is_nothrow_destructible requires that is_destructible is +// satisfied as well. We realize that by mimicing the +// implementation of is_destructible but refer to noexcept(expr) +// instead of decltype(expr). +struct __do_is_nt_destructible_impl { + template + static __bool_constant().~_Tp())> __test(int); - template ::value> - struct __is_signed_helper : public false_type {}; + template + static false_type __test(...); +}; + +template +struct __is_nt_destructible_impl : public __do_is_nt_destructible_impl { + typedef decltype(__test<_Tp>(0)) type; +}; + +template , __is_array_unknown_bounds<_Tp>, + is_function<_Tp>>::value, + bool = __or_, is_scalar<_Tp>>::value> +struct __is_nt_destructible_safe; + +template +struct __is_nt_destructible_safe<_Tp, false, false> + : public __is_nt_destructible_impl< + typename remove_all_extents<_Tp>::type>::type { }; + +template +struct __is_nt_destructible_safe<_Tp, true, false> : public false_type { }; + +template +struct __is_nt_destructible_safe<_Tp, false, true> : public true_type { }; + +/// is_nothrow_destructible +template +struct is_nothrow_destructible : public __is_nt_destructible_safe<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template +struct __is_constructible_impl + : public __bool_constant<__is_constructible(_Tp, _Args...)> { }; + +/// is_constructible +template +struct is_constructible : public __is_constructible_impl<_Tp, _Args...> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_default_constructible +template +struct is_default_constructible : public __is_constructible_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_copy_constructible_impl; + +template +struct __is_copy_constructible_impl<_Tp, false> : public false_type { }; + +template +struct __is_copy_constructible_impl<_Tp, true> + : public __is_constructible_impl<_Tp, const _Tp&> { }; + +/// is_copy_constructible +template +struct is_copy_constructible : public __is_copy_constructible_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_move_constructible_impl; + +template +struct __is_move_constructible_impl<_Tp, false> : public false_type { }; + +template +struct __is_move_constructible_impl<_Tp, true> + : public __is_constructible_impl<_Tp, _Tp&&> { }; + +/// is_move_constructible +template +struct is_move_constructible : public __is_move_constructible_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template +struct __is_nt_constructible_impl : public false_type { }; + +template +struct __is_nt_constructible_impl + : public __bool_constant()...))> { }; + +template +struct __is_nt_constructible_impl + : public __bool_constant(std::declval<_Arg>()))> { +}; + +template +struct __is_nt_constructible_impl + : public __bool_constant { }; + +template +struct __is_nt_constructible_impl + : public __bool_constant< + noexcept(typename remove_all_extents<_Tp>::type())> { }; - template - struct __is_signed_helper<_Tp, true> - : public integral_constant {}; +#if __cpp_aggregate_paren_init +template +struct __is_nt_constructible_impl + : public __is_nt_constructible_impl { }; - /// is_signed - template - struct is_signed : public __is_signed_helper<_Tp>::type {}; +template +struct __is_nt_constructible_impl + : public __and_<__is_nt_constructible_impl...> { }; +#endif - /// is_unsigned - template - struct is_unsigned - : public __and_, __not_>> {}; +template +using __is_nothrow_constructible_impl + = __is_nt_constructible_impl<__is_constructible(_Tp, _Args...), _Tp, + _Args...>; + +/// is_nothrow_constructible +template +struct is_nothrow_constructible + : public __is_nothrow_constructible_impl<_Tp, _Args...>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_nothrow_default_constructible +template +struct is_nothrow_default_constructible + : public __is_nothrow_constructible_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_nothrow_copy_constructible_impl; + +template +struct __is_nothrow_copy_constructible_impl<_Tp, false> : public false_type { }; + +template +struct __is_nothrow_copy_constructible_impl<_Tp, true> + : public __is_nothrow_constructible_impl<_Tp, const _Tp&> { }; + +/// is_nothrow_copy_constructible +template +struct is_nothrow_copy_constructible + : public __is_nothrow_copy_constructible_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_nothrow_move_constructible_impl; + +template +struct __is_nothrow_move_constructible_impl<_Tp, false> : public false_type { }; + +template +struct __is_nothrow_move_constructible_impl<_Tp, true> + : public __is_nothrow_constructible_impl<_Tp, _Tp&&> { }; + +/// is_nothrow_move_constructible +template +struct is_nothrow_move_constructible + : public __is_nothrow_move_constructible_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_assignable +template +struct is_assignable : public __bool_constant<__is_assignable(_Tp, _Up)> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_copy_assignable_impl; + +template +struct __is_copy_assignable_impl<_Tp, false> : public false_type { }; + +template +struct __is_copy_assignable_impl<_Tp, true> + : public __bool_constant<__is_assignable(_Tp&, const _Tp&)> { }; + +/// is_copy_assignable +template +struct is_copy_assignable : public __is_copy_assignable_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_move_assignable_impl; + +template +struct __is_move_assignable_impl<_Tp, false> : public false_type { }; + +template +struct __is_move_assignable_impl<_Tp, true> + : public __bool_constant<__is_assignable(_Tp&, _Tp&&)> { }; + +/// is_move_assignable +template +struct is_move_assignable : public __is_move_assignable_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template +struct __is_nt_assignable_impl + : public integral_constant() = declval<_Up>())> { }; + +template +struct __is_nothrow_assignable_impl + : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>, + __is_nt_assignable_impl<_Tp, _Up>> { }; + +/// is_nothrow_assignable +template +struct is_nothrow_assignable : public __is_nothrow_assignable_impl<_Tp, _Up> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_nt_copy_assignable_impl; + +template +struct __is_nt_copy_assignable_impl<_Tp, false> : public false_type { }; + +template +struct __is_nt_copy_assignable_impl<_Tp, true> + : public __is_nothrow_assignable_impl<_Tp&, const _Tp&> { }; + +/// is_nothrow_copy_assignable +template +struct is_nothrow_copy_assignable : public __is_nt_copy_assignable_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_nt_move_assignable_impl; + +template +struct __is_nt_move_assignable_impl<_Tp, false> : public false_type { }; + +template +struct __is_nt_move_assignable_impl<_Tp, true> + : public __is_nothrow_assignable_impl<_Tp&, _Tp&&> { }; + +/// is_nothrow_move_assignable +template +struct is_nothrow_move_assignable : public __is_nt_move_assignable_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_trivially_constructible +template +struct is_trivially_constructible + : public __bool_constant<__is_trivially_constructible(_Tp, _Args...)> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_trivially_default_constructible +template +struct is_trivially_default_constructible + : public __bool_constant<__is_trivially_constructible(_Tp)> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +struct __do_is_implicitly_default_constructible_impl { + template + static void __helper(const _Tp&); + + template + static true_type + __test(const _Tp&, decltype(__helper({}))* = 0); + + static false_type __test(...); +}; + +template +struct __is_implicitly_default_constructible_impl + : public __do_is_implicitly_default_constructible_impl { + typedef decltype(__test(declval<_Tp>())) type; +}; + +template +struct __is_implicitly_default_constructible_safe + : public __is_implicitly_default_constructible_impl<_Tp>::type { }; + +template +struct __is_implicitly_default_constructible + : public __and_<__is_constructible_impl<_Tp>, + __is_implicitly_default_constructible_safe<_Tp>> { }; + +template ::value> +struct __is_trivially_copy_constructible_impl; + +template +struct __is_trivially_copy_constructible_impl<_Tp, false> : public false_type { +}; + +template +struct __is_trivially_copy_constructible_impl<_Tp, true> + : public __and_<__is_copy_constructible_impl<_Tp>, + integral_constant< + bool, __is_trivially_constructible(_Tp, const _Tp&)>> { }; + +/// is_trivially_copy_constructible +template +struct is_trivially_copy_constructible + : public __is_trivially_copy_constructible_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_trivially_move_constructible_impl; + +template +struct __is_trivially_move_constructible_impl<_Tp, false> : public false_type { +}; + +template +struct __is_trivially_move_constructible_impl<_Tp, true> + : public __and_< + __is_move_constructible_impl<_Tp>, + integral_constant> { }; + +/// is_trivially_move_constructible +template +struct is_trivially_move_constructible + : public __is_trivially_move_constructible_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_trivially_assignable +template +struct is_trivially_assignable + : public __bool_constant<__is_trivially_assignable(_Tp, _Up)> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_trivially_copy_assignable_impl; + +template +struct __is_trivially_copy_assignable_impl<_Tp, false> : public false_type { }; + +template +struct __is_trivially_copy_assignable_impl<_Tp, true> + : public __bool_constant<__is_trivially_assignable(_Tp&, const _Tp&)> { }; + +/// is_trivially_copy_assignable +template +struct is_trivially_copy_assignable + : public __is_trivially_copy_assignable_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template ::value> +struct __is_trivially_move_assignable_impl; + +template +struct __is_trivially_move_assignable_impl<_Tp, false> : public false_type { }; + +template +struct __is_trivially_move_assignable_impl<_Tp, true> + : public __bool_constant<__is_trivially_assignable(_Tp&, _Tp&&)> { }; + +/// is_trivially_move_assignable +template +struct is_trivially_move_assignable + : public __is_trivially_move_assignable_impl<_Tp> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_trivially_destructible +template +struct is_trivially_destructible + : public __and_<__is_destructible_safe<_Tp>, + __bool_constant<__has_trivial_destructor(_Tp)>> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// has_virtual_destructor +template +struct has_virtual_destructor + : public integral_constant { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +// type property queries. + +/// alignment_of +template +struct alignment_of : public integral_constant { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// rank +template +struct rank : public integral_constant { }; + +template +struct rank<_Tp[_Size]> + : public integral_constant::value> { }; + +template +struct rank<_Tp[]> : public integral_constant::value> { }; + +/// extent +template +struct extent : public integral_constant { }; + +template +struct extent<_Tp[_Size], _Uint> + : public integral_constant< + size_t, _Uint == 0 ? _Size : extent<_Tp, _Uint - 1>::value> { }; + +template +struct extent<_Tp[], _Uint> + : public integral_constant::value> { +}; + +// Type relations. + +/// is_same +template +struct is_same +#ifdef _GLIBCXX_BUILTIN_IS_SAME_AS + : public integral_constant +#else + : public false_type +#endif +{ +}; - // Destructible and constructible type properties. +#ifndef _GLIBCXX_BUILTIN_IS_SAME_AS +template +struct is_same<_Tp, _Tp> : public true_type { }; +#endif - /** - * @brief Utility to simplify expressions used in unevaluated operands - * @ingroup utilities - */ +/// is_base_of +template +struct is_base_of + : public integral_constant { }; - template - _Up __declval(int); +template , is_function<_To>, is_array<_To>>::value> +struct __is_convertible_helper { + typedef typename is_void<_To>::type type; +}; - template - _Tp __declval(long); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" - template - auto declval() noexcept -> decltype(__declval<_Tp>(0)); +template +class __is_convertible_helper<_From, _To, false> { + template + static void __test_aux(_To1) noexcept; - template - struct extent; + template (std::declval<_From1>()))> + static true_type __test(int); - template - struct remove_all_extents; + template + static false_type __test(...); - template - struct __is_array_known_bounds - : public integral_constant::value > 0)> {}; +public: + typedef decltype(__test<_From, _To>(0)) type; +}; - template - struct __is_array_unknown_bounds - : public __and_, __not_>> {}; - - // In N3290 is_destructible does not say anything about function - // types and abstract types, see LWG 2049. This implementation - // describes function types as non-destructible and all complete - // object types as destructible, iff the explicit destructor - // call expression is wellformed. - struct __do_is_destructible_impl { - template ().~_Tp())> - static true_type __test(int); - - template - static false_type __test(...); - }; +#pragma GCC diagnostic pop - template - struct __is_destructible_impl : public __do_is_destructible_impl { - typedef decltype(__test<_Tp>(0)) type; - }; +/// is_convertible +template +struct is_convertible : public __is_convertible_helper<_From, _To>::type { }; - template , __is_array_unknown_bounds<_Tp>, - is_function<_Tp>>::value, - bool = __or_, is_scalar<_Tp>>::value> - struct __is_destructible_safe; +// helper trait for unique_ptr, shared_ptr, and span +template +using __is_array_convertible + = is_convertible<_FromElementType (*)[], _ToElementType (*)[]>; - template - struct __is_destructible_safe<_Tp, false, false> - : public __is_destructible_impl< - typename remove_all_extents<_Tp>::type>::type {}; +template , is_function<_To>, is_array<_To>>::value> +struct __is_nt_convertible_helper : is_void<_To> { }; - template - struct __is_destructible_safe<_Tp, true, false> : public false_type {}; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" - template - struct __is_destructible_safe<_Tp, false, true> : public true_type {}; +template +class __is_nt_convertible_helper<_From, _To, false> { + template + static void __test_aux(_To1) noexcept; - /// is_destructible - template - struct is_destructible : public __is_destructible_safe<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; + template + static __bool_constant(std::declval<_From1>()))> + __test(int); - // is_nothrow_destructible requires that is_destructible is - // satisfied as well. We realize that by mimicing the - // implementation of is_destructible but refer to noexcept(expr) - // instead of decltype(expr). - struct __do_is_nt_destructible_impl { - template - static __bool_constant().~_Tp())> __test(int); + template + static false_type __test(...); - template - static false_type __test(...); - }; +public: + using type = decltype(__test<_From, _To>(0)); +}; - template - struct __is_nt_destructible_impl : public __do_is_nt_destructible_impl { - typedef decltype(__test<_Tp>(0)) type; - }; +#pragma GCC diagnostic pop - template , __is_array_unknown_bounds<_Tp>, - is_function<_Tp>>::value, - bool = __or_, is_scalar<_Tp>>::value> - struct __is_nt_destructible_safe; +// is_nothrow_convertible for C++11 +template +struct __is_nothrow_convertible + : public __is_nt_convertible_helper<_From, _To>::type { }; - template - struct __is_nt_destructible_safe<_Tp, false, false> - : public __is_nt_destructible_impl< - typename remove_all_extents<_Tp>::type>::type {}; +#if __cplusplus > 201703L +# define __cpp_lib_is_nothrow_convertible 201806L + +/// is_nothrow_convertible +template +struct is_nothrow_convertible + : public __is_nt_convertible_helper<_From, _To>::type { }; + +/// is_nothrow_convertible_v +template +inline constexpr bool is_nothrow_convertible_v + = is_nothrow_convertible<_From, _To>::value; +#endif // C++2a + +// Const-volatile modifications. + +/// remove_const +template +struct remove_const { + typedef _Tp type; +}; + +template +struct remove_const { + typedef _Tp type; +}; + +/// remove_volatile +template +struct remove_volatile { + typedef _Tp type; +}; + +template +struct remove_volatile { + typedef _Tp type; +}; + +/// remove_cv +template +struct remove_cv { + using type = _Tp; +}; + +template +struct remove_cv { + using type = _Tp; +}; + +template +struct remove_cv { + using type = _Tp; +}; + +template +struct remove_cv { + using type = _Tp; +}; + +/// add_const +template +struct add_const { + typedef const _Tp type; +}; + +/// add_volatile +template +struct add_volatile { + typedef volatile _Tp type; +}; + +/// add_cv +template +struct add_cv { + typedef typename add_const::type>::type type; +}; - template - struct __is_nt_destructible_safe<_Tp, true, false> : public false_type {}; +#if __cplusplus > 201103L - template - struct __is_nt_destructible_safe<_Tp, false, true> : public true_type {}; +# define __cpp_lib_transformation_trait_aliases 201304 - /// is_nothrow_destructible - template - struct is_nothrow_destructible - : public __is_nt_destructible_safe<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +/// Alias template for remove_const +template +using remove_const_t = typename remove_const<_Tp>::type; - template - struct __is_constructible_impl - : public __bool_constant<__is_constructible(_Tp, _Args...)> {}; +/// Alias template for remove_volatile +template +using remove_volatile_t = typename remove_volatile<_Tp>::type; - /// is_constructible - template - struct is_constructible : public __is_constructible_impl<_Tp, _Args...> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +/// Alias template for remove_cv +template +using remove_cv_t = typename remove_cv<_Tp>::type; - /// is_default_constructible - template - struct is_default_constructible - : public __is_constructible_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +/// Alias template for add_const +template +using add_const_t = typename add_const<_Tp>::type; - template ::value> - struct __is_copy_constructible_impl; +/// Alias template for add_volatile +template +using add_volatile_t = typename add_volatile<_Tp>::type; - template - struct __is_copy_constructible_impl<_Tp, false> : public false_type {}; +/// Alias template for add_cv +template +using add_cv_t = typename add_cv<_Tp>::type; +#endif - template - struct __is_copy_constructible_impl<_Tp, true> - : public __is_constructible_impl<_Tp, const _Tp &> {}; +// Reference transformations. - /// is_copy_constructible - template - struct is_copy_constructible : public __is_copy_constructible_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +/// remove_reference +template +struct remove_reference { + typedef _Tp type; +}; - template ::value> - struct __is_move_constructible_impl; +template +struct remove_reference<_Tp&> { + typedef _Tp type; +}; - template - struct __is_move_constructible_impl<_Tp, false> : public false_type {}; +template +struct remove_reference<_Tp&&> { + typedef _Tp type; +}; - template - struct __is_move_constructible_impl<_Tp, true> - : public __is_constructible_impl<_Tp, _Tp &&> {}; +template ::value> +struct __add_lvalue_reference_helper { + typedef _Tp type; +}; - /// is_move_constructible - template - struct is_move_constructible : public __is_move_constructible_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +struct __add_lvalue_reference_helper<_Tp, true> { + typedef _Tp& type; +}; - template - struct __is_nt_constructible_impl : public false_type {}; +/// add_lvalue_reference +template +struct add_lvalue_reference : public __add_lvalue_reference_helper<_Tp> { }; - template - struct __is_nt_constructible_impl - : public __bool_constant()...))> {}; +template ::value> +struct __add_rvalue_reference_helper { + typedef _Tp type; +}; - template - struct __is_nt_constructible_impl - : public __bool_constant(std::declval<_Arg>()))> {}; +template +struct __add_rvalue_reference_helper<_Tp, true> { + typedef _Tp&& type; +}; - template - struct __is_nt_constructible_impl - : public __bool_constant {}; +/// add_rvalue_reference +template +struct add_rvalue_reference : public __add_rvalue_reference_helper<_Tp> { }; - template - struct __is_nt_constructible_impl - : public __bool_constant::type())> {}; +#if __cplusplus > 201103L +/// Alias template for remove_reference +template +using remove_reference_t = typename remove_reference<_Tp>::type; -#if __cpp_aggregate_paren_init - template - struct __is_nt_constructible_impl - : public __is_nt_constructible_impl {}; +/// Alias template for add_lvalue_reference +template +using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; - template - struct __is_nt_constructible_impl - : public __and_<__is_nt_constructible_impl...> {}; +/// Alias template for add_rvalue_reference +template +using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; #endif - template - using __is_nothrow_constructible_impl = - __is_nt_constructible_impl<__is_constructible(_Tp, _Args...), _Tp, - _Args...>; - - /// is_nothrow_constructible - template - struct is_nothrow_constructible - : public __is_nothrow_constructible_impl<_Tp, _Args...>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +// Sign modifications. + +// Utility for constructing identically cv-qualified types. +template +struct __cv_selector; + +template +struct __cv_selector<_Unqualified, false, false> { + typedef _Unqualified __type; +}; + +template +struct __cv_selector<_Unqualified, false, true> { + typedef volatile _Unqualified __type; +}; + +template +struct __cv_selector<_Unqualified, true, false> { + typedef const _Unqualified __type; +}; + +template +struct __cv_selector<_Unqualified, true, true> { + typedef const volatile _Unqualified __type; +}; + +template ::value, + bool _IsVol = is_volatile<_Qualified>::value> +class __match_cv_qualifiers { + typedef __cv_selector<_Unqualified, _IsConst, _IsVol> __match; + +public: + typedef typename __match::__type __type; +}; + +// Utility for finding the unsigned versions of signed integral types. +template +struct __make_unsigned { + typedef _Tp __type; +}; + +template <> +struct __make_unsigned { + typedef unsigned char __type; +}; + +template <> +struct __make_unsigned { + typedef unsigned char __type; +}; + +template <> +struct __make_unsigned { + typedef unsigned short __type; +}; + +template <> +struct __make_unsigned { + typedef unsigned int __type; +}; + +template <> +struct __make_unsigned { + typedef unsigned long __type; +}; + +template <> +struct __make_unsigned { + typedef unsigned long long __type; +}; - /// is_nothrow_default_constructible - template - struct is_nothrow_default_constructible - : public __is_nothrow_constructible_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +#if defined(__GLIBCXX_TYPE_INT_N_0) +template <> +struct __make_unsigned<__GLIBCXX_TYPE_INT_N_0> { + typedef unsigned __GLIBCXX_TYPE_INT_N_0 __type; +}; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) +template <> +struct __make_unsigned<__GLIBCXX_TYPE_INT_N_1> { + typedef unsigned __GLIBCXX_TYPE_INT_N_1 __type; +}; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) +template <> +struct __make_unsigned<__GLIBCXX_TYPE_INT_N_2> { + typedef unsigned __GLIBCXX_TYPE_INT_N_2 __type; +}; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_3) +template <> +struct __make_unsigned<__GLIBCXX_TYPE_INT_N_3> { + typedef unsigned __GLIBCXX_TYPE_INT_N_3 __type; +}; +#endif - template ::value> - struct __is_nothrow_copy_constructible_impl; +// Select between integral and enum: not possible to be both. +template ::value, + bool _IsEnum = is_enum<_Tp>::value> +class __make_unsigned_selector; - template - struct __is_nothrow_copy_constructible_impl<_Tp, false> - : public false_type {}; +template +class __make_unsigned_selector<_Tp, true, false> { + using __unsigned_type = + typename __make_unsigned<__remove_cv_t<_Tp>>::__type; - template - struct __is_nothrow_copy_constructible_impl<_Tp, true> - : public __is_nothrow_constructible_impl<_Tp, const _Tp &> {}; +public: + using __type = typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type; +}; - /// is_nothrow_copy_constructible - template - struct is_nothrow_copy_constructible - : public __is_nothrow_copy_constructible_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); +class __make_unsigned_selector_base { +protected: + template + struct _List { }; + + template + struct _List<_Tp, _Up...> : _List<_Up...> { + static constexpr size_t __size = sizeof(_Tp); }; - template ::value> - struct __is_nothrow_move_constructible_impl; + template + struct __select; - template - struct __is_nothrow_move_constructible_impl<_Tp, false> - : public false_type {}; + template + struct __select<_Sz, _List<_Uint, _UInts...>, true> { + using __type = _Uint; + }; - template - struct __is_nothrow_move_constructible_impl<_Tp, true> - : public __is_nothrow_constructible_impl<_Tp, _Tp &&> {}; + template + struct __select<_Sz, _List<_Uint, _UInts...>, false> + : __select<_Sz, _List<_UInts...>> { }; +}; - /// is_nothrow_move_constructible - template - struct is_nothrow_move_constructible - : public __is_nothrow_move_constructible_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +// Choose unsigned integer type with the smallest rank and same size as _Tp +template +class __make_unsigned_selector<_Tp, false, true> + : __make_unsigned_selector_base { + // With -fshort-enums, an enum may be as small as a char. + using _UInts = _List; - /// is_assignable - template - struct is_assignable : public __bool_constant<__is_assignable(_Tp, _Up)> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; + using __unsigned_type = typename __select::__type; - template ::value> - struct __is_copy_assignable_impl; +public: + using __type = typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type; +}; - template - struct __is_copy_assignable_impl<_Tp, false> : public false_type {}; +// int, char8_t, char16_t and char32_t are integral types but are +// neither signed integer types nor unsigned integer types, so must be +// transformed to the unsigned integer type with the smallest rank. +// Use the partial specialization for enumeration types to do that. +#if defined(_GLIBCXX_USE_WCHAR_T) +template <> +struct __make_unsigned { + using __type = typename __make_unsigned_selector::__type; +}; +#endif - template - struct __is_copy_assignable_impl<_Tp, true> - : public __bool_constant<__is_assignable(_Tp &, const _Tp &)> {}; +#ifdef _GLIBCXX_USE_CHAR8_T +template <> +struct __make_unsigned { + using __type = + typename __make_unsigned_selector::__type; +}; +#endif - /// is_copy_assignable - template - struct is_copy_assignable : public __is_copy_assignable_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template <> +struct __make_unsigned { + using __type = + typename __make_unsigned_selector::__type; +}; + +template <> +struct __make_unsigned { + using __type = + typename __make_unsigned_selector::__type; +}; + +// Given an integral/enum type, return the corresponding unsigned +// integer type. +// Primary template. +/// make_unsigned +template +struct make_unsigned { + typedef typename __make_unsigned_selector<_Tp>::__type type; +}; + +// Integral, but don't define. +template <> +struct make_unsigned; + +// Utility for finding the signed versions of unsigned integral types. +template +struct __make_signed { + typedef _Tp __type; +}; + +template <> +struct __make_signed { + typedef signed char __type; +}; + +template <> +struct __make_signed { + typedef signed char __type; +}; + +template <> +struct __make_signed { + typedef signed short __type; +}; + +template <> +struct __make_signed { + typedef signed int __type; +}; + +template <> +struct __make_signed { + typedef signed long __type; +}; + +template <> +struct __make_signed { + typedef signed long long __type; +}; - template ::value> - struct __is_move_assignable_impl; +#if defined(__GLIBCXX_TYPE_INT_N_0) +template <> +struct __make_signed { + typedef __GLIBCXX_TYPE_INT_N_0 __type; +}; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) +template <> +struct __make_signed { + typedef __GLIBCXX_TYPE_INT_N_1 __type; +}; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) +template <> +struct __make_signed { + typedef __GLIBCXX_TYPE_INT_N_2 __type; +}; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_3) +template <> +struct __make_signed { + typedef __GLIBCXX_TYPE_INT_N_3 __type; +}; +#endif - template - struct __is_move_assignable_impl<_Tp, false> : public false_type {}; +// Select between integral and enum: not possible to be both. +template ::value, + bool _IsEnum = is_enum<_Tp>::value> +class __make_signed_selector; - template - struct __is_move_assignable_impl<_Tp, true> - : public __bool_constant<__is_assignable(_Tp &, _Tp &&)> {}; +template +class __make_signed_selector<_Tp, true, false> { + using __signed_type = typename __make_signed<__remove_cv_t<_Tp>>::__type; - /// is_move_assignable - template - struct is_move_assignable : public __is_move_assignable_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +public: + using __type = typename __match_cv_qualifiers<_Tp, __signed_type>::__type; +}; - template - struct __is_nt_assignable_impl - : public integral_constant() = declval<_Up>())> { - }; +// Choose signed integer type with the smallest rank and same size as _Tp +template +class __make_signed_selector<_Tp, false, true> { + typedef typename __make_unsigned_selector<_Tp>::__type __unsigned_type; - template - struct __is_nothrow_assignable_impl - : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>, - __is_nt_assignable_impl<_Tp, _Up>> {}; +public: + typedef typename __make_signed_selector<__unsigned_type>::__type __type; +}; - /// is_nothrow_assignable - template - struct is_nothrow_assignable - : public __is_nothrow_assignable_impl<_Tp, _Up> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +// int, char16_t and char32_t are integral types but are neither +// signed integer types nor unsigned integer types, so must be +// transformed to the signed integer type with the smallest rank. +// Use the partial specialization for enumeration types to do that. +#if defined(_GLIBCXX_USE_WCHAR_T) +template <> +struct __make_signed { + using __type = typename __make_signed_selector::__type; +}; +#endif - template ::value> - struct __is_nt_copy_assignable_impl; +#if defined(_GLIBCXX_USE_CHAR8_T) +template <> +struct __make_signed { + using __type = + typename __make_signed_selector::__type; +}; +#endif - template - struct __is_nt_copy_assignable_impl<_Tp, false> : public false_type {}; +template <> +struct __make_signed { + using __type = + typename __make_signed_selector::__type; +}; + +template <> +struct __make_signed { + using __type = + typename __make_signed_selector::__type; +}; + +// Given an integral/enum type, return the corresponding signed +// integer type. +// Primary template. +/// make_signed +template +struct make_signed { + typedef typename __make_signed_selector<_Tp>::__type type; +}; + +// Integral, but don't define. +template <> +struct make_signed; - template - struct __is_nt_copy_assignable_impl<_Tp, true> - : public __is_nothrow_assignable_impl<_Tp &, const _Tp &> {}; +#if __cplusplus > 201103L +/// Alias template for make_signed +template +using make_signed_t = typename make_signed<_Tp>::type; - /// is_nothrow_copy_assignable - template - struct is_nothrow_copy_assignable - : public __is_nt_copy_assignable_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +/// Alias template for make_unsigned +template +using make_unsigned_t = typename make_unsigned<_Tp>::type; +#endif - template ::value> - struct __is_nt_move_assignable_impl; +// Array modifications. - template - struct __is_nt_move_assignable_impl<_Tp, false> : public false_type {}; +/// remove_extent +template +struct remove_extent { + typedef _Tp type; +}; - template - struct __is_nt_move_assignable_impl<_Tp, true> - : public __is_nothrow_assignable_impl<_Tp &, _Tp &&> {}; +template +struct remove_extent<_Tp[_Size]> { + typedef _Tp type; +}; - /// is_nothrow_move_assignable - template - struct is_nothrow_move_assignable - : public __is_nt_move_assignable_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +struct remove_extent<_Tp[]> { + typedef _Tp type; +}; - /// is_trivially_constructible - template - struct is_trivially_constructible - : public __bool_constant<__is_trivially_constructible(_Tp, _Args...)> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +/// remove_all_extents +template +struct remove_all_extents { + typedef _Tp type; +}; - /// is_trivially_default_constructible - template - struct is_trivially_default_constructible - : public __bool_constant<__is_trivially_constructible(_Tp)> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +struct remove_all_extents<_Tp[_Size]> { + typedef typename remove_all_extents<_Tp>::type type; +}; - struct __do_is_implicitly_default_constructible_impl { - template - static void __helper(const _Tp &); +template +struct remove_all_extents<_Tp[]> { + typedef typename remove_all_extents<_Tp>::type type; +}; - template - static true_type __test(const _Tp &, - decltype(__helper({})) * = 0); +#if __cplusplus > 201103L +/// Alias template for remove_extent +template +using remove_extent_t = typename remove_extent<_Tp>::type; - static false_type __test(...); - }; +/// Alias template for remove_all_extents +template +using remove_all_extents_t = typename remove_all_extents<_Tp>::type; +#endif - template - struct __is_implicitly_default_constructible_impl - : public __do_is_implicitly_default_constructible_impl { - typedef decltype(__test(declval<_Tp>())) type; - }; +// Pointer modifications. - template - struct __is_implicitly_default_constructible_safe - : public __is_implicitly_default_constructible_impl<_Tp>::type {}; +template +struct __remove_pointer_helper { + typedef _Tp type; +}; - template - struct __is_implicitly_default_constructible - : public __and_<__is_constructible_impl<_Tp>, - __is_implicitly_default_constructible_safe<_Tp>> {}; +template +struct __remove_pointer_helper<_Tp, _Up*> { + typedef _Up type; +}; - template ::value> - struct __is_trivially_copy_constructible_impl; +/// remove_pointer +template +struct remove_pointer + : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>> { }; - template - struct __is_trivially_copy_constructible_impl<_Tp, false> - : public false_type {}; +/// add_pointer +template , is_void<_Tp>>::value> +struct __add_pointer_helper { + typedef _Tp type; +}; - template - struct __is_trivially_copy_constructible_impl<_Tp, true> - : public __and_<__is_copy_constructible_impl<_Tp>, - integral_constant> {}; +template +struct __add_pointer_helper<_Tp, true> { + typedef typename remove_reference<_Tp>::type* type; +}; - /// is_trivially_copy_constructible - template - struct is_trivially_copy_constructible - : public __is_trivially_copy_constructible_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +template +struct add_pointer : public __add_pointer_helper<_Tp> { }; - template ::value> - struct __is_trivially_move_constructible_impl; +#if __cplusplus > 201103L +/// Alias template for remove_pointer +template +using remove_pointer_t = typename remove_pointer<_Tp>::type; - template - struct __is_trivially_move_constructible_impl<_Tp, false> - : public false_type {}; +/// Alias template for add_pointer +template +using add_pointer_t = typename add_pointer<_Tp>::type; +#endif - template - struct __is_trivially_move_constructible_impl<_Tp, true> - : public __and_<__is_move_constructible_impl<_Tp>, - integral_constant> {}; +template +struct __aligned_storage_msa { + union __type { + unsigned char __data[_Len]; + + struct __attribute__((__aligned__)) { + } __align; + }; +}; + +/** + * @brief Alignment type. + * + * The value of _Align is a default-alignment which shall be the + * most stringent alignment requirement for any C++ object type + * whose size is no greater than _Len (3.9). The member typedef + * type shall be a POD type suitable for use as uninitialized + * storage for any object whose size is at most _Len and whose + * alignment is a divisor of _Align. + */ +template ::__type)> +struct aligned_storage { + union type { + unsigned char __data[_Len]; + + struct __attribute__((__aligned__((_Align)))) { + } __align; + }; +}; + +template +struct __strictest_alignment { + static const size_t _S_alignment = 0; + static const size_t _S_size = 0; +}; + +template +struct __strictest_alignment<_Tp, _Types...> { + static const size_t _S_alignment + = alignof(_Tp) > __strictest_alignment<_Types...>::_S_alignment + ? alignof(_Tp) + : __strictest_alignment<_Types...>::_S_alignment; + static const size_t _S_size + = sizeof(_Tp) > __strictest_alignment<_Types...>::_S_size + ? sizeof(_Tp) + : __strictest_alignment<_Types...>::_S_size; +}; + +/** + * @brief Provide aligned storage for types. + * + * [meta.trans.other] + * + * Provides aligned storage for any of the provided types of at + * least size _Len. + * + * @see aligned_storage + */ +template +struct aligned_union { +private: + static_assert(sizeof...(_Types) != 0, "At least one type is required"); + + using __strictest = __strictest_alignment<_Types...>; + static const size_t _S_len + = _Len > __strictest::_S_size ? _Len : __strictest::_S_size; + +public: + /// The value of the strictest alignment of _Types. + static const size_t alignment_value = __strictest::_S_alignment; + /// The storage. + typedef typename aligned_storage<_S_len, alignment_value>::type type; +}; + +template +const size_t aligned_union<_Len, _Types...>::alignment_value; + +// Decay trait for arrays and functions, used for perfect forwarding +// in make_pair, make_tuple, etc. +template ::value, + bool _IsFunction = is_function<_Up>::value> +struct __decay_selector; + +// NB: DR 705. +template +struct __decay_selector<_Up, false, false> { + typedef __remove_cv_t<_Up> __type; +}; + +template +struct __decay_selector<_Up, true, false> { + typedef typename remove_extent<_Up>::type* __type; +}; + +template +struct __decay_selector<_Up, false, true> { + typedef typename add_pointer<_Up>::type __type; +}; + +/// decay +template +class decay { + typedef typename remove_reference<_Tp>::type __remove_type; + +public: + typedef typename __decay_selector<__remove_type>::__type type; +}; + +// __decay_t (std::decay_t for C++11). +template +using __decay_t = typename decay<_Tp>::type; + +template +class reference_wrapper; + +// Helper which adds a reference to a type when given a reference_wrapper +template +struct __strip_reference_wrapper { + typedef _Tp __type; +}; + +template +struct __strip_reference_wrapper> { + typedef _Tp& __type; +}; + +template +using __decay_and_strip = __strip_reference_wrapper<__decay_t<_Tp>>; + +// Primary template. +/// Define a member typedef @c type only if a boolean constant is true. +template +struct enable_if { }; + +// Partial specialization for true. +template +struct enable_if { + typedef _Tp type; +}; + +// __enable_if_t (std::enable_if_t for C++11) +template +using __enable_if_t = typename enable_if<_Cond, _Tp>::type; + +template +using _Require = __enable_if_t<__and_<_Cond...>::value>; + +// Primary template. +/// Define a member typedef @c type to one of two argument types. +template +struct conditional { + typedef _Iftrue type; +}; + +// Partial specialization for false. +template +struct conditional { + typedef _Iffalse type; +}; + +// __remove_cvref_t (std::remove_cvref_t for C++11). +template +using __remove_cvref_t = + typename remove_cv::type>::type; + +/// common_type +template +struct common_type; + +// Sfinae-friendly common_type implementation: + +struct __do_common_type_impl { + template + using __cond_t = decltype(true ? std::declval<_Tp>() : std::declval<_Up>()); - /// is_trivially_move_constructible - template - struct is_trivially_move_constructible - : public __is_trivially_move_constructible_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; + // if decay_t() : declval())> + // denotes a valid type, let C denote that type. + template + static __success_type<__decay_t<__cond_t<_Tp, _Up>>> _S_test(int); - /// is_trivially_assignable +#if __cplusplus > 201703L + // Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, + // let C denote the type decay_t. template - struct is_trivially_assignable - : public __bool_constant<__is_trivially_assignable(_Tp, _Up)> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; + static __success_type<__remove_cvref_t<__cond_t>> + _S_test_2(int); +#endif - template ::value> - struct __is_trivially_copy_assignable_impl; + template + static __failure_type _S_test_2(...); - template - struct __is_trivially_copy_assignable_impl<_Tp, false> : public false_type { - }; - - template - struct __is_trivially_copy_assignable_impl<_Tp, true> - : public __bool_constant<__is_trivially_assignable(_Tp &, - const _Tp &)> {}; - - /// is_trivially_copy_assignable - template - struct is_trivially_copy_assignable - : public __is_trivially_copy_assignable_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; - - template ::value> - struct __is_trivially_move_assignable_impl; - - template - struct __is_trivially_move_assignable_impl<_Tp, false> : public false_type { - }; - - template - struct __is_trivially_move_assignable_impl<_Tp, true> - : public __bool_constant<__is_trivially_assignable(_Tp &, _Tp &&)> {}; - - /// is_trivially_move_assignable - template - struct is_trivially_move_assignable - : public __is_trivially_move_assignable_impl<_Tp> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; - - /// is_trivially_destructible - template - struct is_trivially_destructible - : public __and_<__is_destructible_safe<_Tp>, - __bool_constant<__has_trivial_destructor(_Tp)>> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; - - /// has_virtual_destructor - template - struct has_virtual_destructor - : public integral_constant { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; - - // type property queries. - - /// alignment_of - template - struct alignment_of : public integral_constant { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; - - /// rank - template - struct rank : public integral_constant {}; - - template - struct rank<_Tp[_Size]> - : public integral_constant::value> {}; - - template - struct rank<_Tp[]> - : public integral_constant::value> {}; - - /// extent - template - struct extent : public integral_constant {}; - - template - struct extent<_Tp[_Size], _Uint> - : public integral_constant< - size_t, _Uint == 0 ? _Size : extent<_Tp, _Uint - 1>::value> {}; - - template - struct extent<_Tp[], _Uint> - : public integral_constant< - size_t, _Uint == 0 ? 0 : extent<_Tp, _Uint - 1>::value> {}; - - // Type relations. - - /// is_same - template - struct is_same -#ifdef _GLIBCXX_BUILTIN_IS_SAME_AS - : public integral_constant -#else - : public false_type -#endif - { - }; - -#ifndef _GLIBCXX_BUILTIN_IS_SAME_AS - template - struct is_same<_Tp, _Tp> : public true_type {}; -#endif - - /// is_base_of - template - struct is_base_of - : public integral_constant {}; - - template , is_function<_To>, is_array<_To>>::value> - struct __is_convertible_helper { - typedef typename is_void<_To>::type type; - }; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" - template - class __is_convertible_helper<_From, _To, false> { - template - static void __test_aux(_To1) noexcept; - - template (std::declval<_From1>()))> - static true_type __test(int); - - template - static false_type __test(...); - - public: - typedef decltype(__test<_From, _To>(0)) type; - }; -#pragma GCC diagnostic pop - - /// is_convertible - template - struct is_convertible : public __is_convertible_helper<_From, _To>::type {}; - - // helper trait for unique_ptr, shared_ptr, and span - template - using __is_array_convertible = - is_convertible<_FromElementType (*)[], _ToElementType (*)[]>; - - template , is_function<_To>, is_array<_To>>::value> - struct __is_nt_convertible_helper : is_void<_To> {}; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" - template - class __is_nt_convertible_helper<_From, _To, false> { - template - static void __test_aux(_To1) noexcept; - - template - static __bool_constant< - noexcept(__test_aux<_To1>(std::declval<_From1>()))> - __test(int); - - template - static false_type __test(...); - - public: - using type = decltype(__test<_From, _To>(0)); - }; -#pragma GCC diagnostic pop - - // is_nothrow_convertible for C++11 - template - struct __is_nothrow_convertible - : public __is_nt_convertible_helper<_From, _To>::type {}; - -#if __cplusplus > 201703L -#define __cpp_lib_is_nothrow_convertible 201806L - /// is_nothrow_convertible - template - struct is_nothrow_convertible - : public __is_nt_convertible_helper<_From, _To>::type {}; - - /// is_nothrow_convertible_v - template - inline constexpr bool is_nothrow_convertible_v = - is_nothrow_convertible<_From, _To>::value; -#endif // C++2a - - // Const-volatile modifications. - - /// remove_const - template - struct remove_const { - typedef _Tp type; - }; - - template - struct remove_const<_Tp const> { - typedef _Tp type; - }; - - /// remove_volatile - template - struct remove_volatile { - typedef _Tp type; - }; - - template - struct remove_volatile<_Tp volatile> { - typedef _Tp type; - }; - - /// remove_cv - template - struct remove_cv { - using type = _Tp; - }; - - template - struct remove_cv { - using type = _Tp; - }; - - template - struct remove_cv { - using type = _Tp; - }; - - template - struct remove_cv { - using type = _Tp; - }; - - /// add_const - template - struct add_const { - typedef _Tp const type; - }; - - /// add_volatile - template - struct add_volatile { - typedef _Tp volatile type; - }; - - /// add_cv - template - struct add_cv { - typedef typename add_const::type>::type type; - }; - -#if __cplusplus > 201103L - -#define __cpp_lib_transformation_trait_aliases 201304 - - /// Alias template for remove_const - template - using remove_const_t = typename remove_const<_Tp>::type; - - /// Alias template for remove_volatile - template - using remove_volatile_t = typename remove_volatile<_Tp>::type; - - /// Alias template for remove_cv - template - using remove_cv_t = typename remove_cv<_Tp>::type; - - /// Alias template for add_const - template - using add_const_t = typename add_const<_Tp>::type; - - /// Alias template for add_volatile - template - using add_volatile_t = typename add_volatile<_Tp>::type; - - /// Alias template for add_cv - template - using add_cv_t = typename add_cv<_Tp>::type; -#endif - - // Reference transformations. - - /// remove_reference - template - struct remove_reference { - typedef _Tp type; - }; - - template - struct remove_reference<_Tp &> { - typedef _Tp type; - }; - - template - struct remove_reference<_Tp &&> { - typedef _Tp type; - }; - - template ::value> - struct __add_lvalue_reference_helper { - typedef _Tp type; - }; - - template - struct __add_lvalue_reference_helper<_Tp, true> { - typedef _Tp &type; - }; - - /// add_lvalue_reference - template - struct add_lvalue_reference : public __add_lvalue_reference_helper<_Tp> {}; - - template ::value> - struct __add_rvalue_reference_helper { - typedef _Tp type; - }; - - template - struct __add_rvalue_reference_helper<_Tp, true> { - typedef _Tp &&type; - }; - - /// add_rvalue_reference - template - struct add_rvalue_reference : public __add_rvalue_reference_helper<_Tp> {}; - -#if __cplusplus > 201103L - /// Alias template for remove_reference - template - using remove_reference_t = typename remove_reference<_Tp>::type; - - /// Alias template for add_lvalue_reference - template - using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; - - /// Alias template for add_rvalue_reference - template - using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; -#endif - - // Sign modifications. - - // Utility for constructing identically cv-qualified types. - template - struct __cv_selector; - - template - struct __cv_selector<_Unqualified, false, false> { - typedef _Unqualified __type; - }; - - template - struct __cv_selector<_Unqualified, false, true> { - typedef volatile _Unqualified __type; - }; - - template - struct __cv_selector<_Unqualified, true, false> { - typedef const _Unqualified __type; - }; - - template - struct __cv_selector<_Unqualified, true, true> { - typedef const volatile _Unqualified __type; - }; - - template ::value, - bool _IsVol = is_volatile<_Qualified>::value> - class __match_cv_qualifiers { - typedef __cv_selector<_Unqualified, _IsConst, _IsVol> __match; - - public: - typedef typename __match::__type __type; - }; - - // Utility for finding the unsigned versions of signed integral types. - template - struct __make_unsigned { - typedef _Tp __type; - }; - - template <> - struct __make_unsigned { - typedef unsigned char __type; - }; - - template <> - struct __make_unsigned { - typedef unsigned char __type; - }; - - template <> - struct __make_unsigned { - typedef unsigned short __type; - }; - - template <> - struct __make_unsigned { - typedef unsigned int __type; - }; - - template <> - struct __make_unsigned { - typedef unsigned long __type; - }; - - template <> - struct __make_unsigned { - typedef unsigned long long __type; - }; - -#if defined(__GLIBCXX_TYPE_INT_N_0) - template <> - struct __make_unsigned<__GLIBCXX_TYPE_INT_N_0> { - typedef unsigned __GLIBCXX_TYPE_INT_N_0 __type; - }; -#endif -#if defined(__GLIBCXX_TYPE_INT_N_1) - template <> - struct __make_unsigned<__GLIBCXX_TYPE_INT_N_1> { - typedef unsigned __GLIBCXX_TYPE_INT_N_1 __type; - }; -#endif -#if defined(__GLIBCXX_TYPE_INT_N_2) - template <> - struct __make_unsigned<__GLIBCXX_TYPE_INT_N_2> { - typedef unsigned __GLIBCXX_TYPE_INT_N_2 __type; - }; -#endif -#if defined(__GLIBCXX_TYPE_INT_N_3) - template <> - struct __make_unsigned<__GLIBCXX_TYPE_INT_N_3> { - typedef unsigned __GLIBCXX_TYPE_INT_N_3 __type; - }; -#endif - - // Select between integral and enum: not possible to be both. - template ::value, - bool _IsEnum = is_enum<_Tp>::value> - class __make_unsigned_selector; - - template - class __make_unsigned_selector<_Tp, true, false> { - using __unsigned_type = - typename __make_unsigned<__remove_cv_t<_Tp>>::__type; - - public: - using __type = - typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type; - }; - - class __make_unsigned_selector_base { - protected: - template - struct _List {}; - - template - struct _List<_Tp, _Up...> : _List<_Up...> { - static constexpr size_t __size = sizeof(_Tp); - }; - - template - struct __select; - - template - struct __select<_Sz, _List<_Uint, _UInts...>, true> { - using __type = _Uint; - }; - - template - struct __select<_Sz, _List<_Uint, _UInts...>, false> - : __select<_Sz, _List<_UInts...>> {}; - }; - - // Choose unsigned integer type with the smallest rank and same size as _Tp - template - class __make_unsigned_selector<_Tp, false, true> - : __make_unsigned_selector_base { - // With -fshort-enums, an enum may be as small as a char. - using _UInts = _List; - - using __unsigned_type = typename __select::__type; - - public: - using __type = - typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type; - }; - - // int, char8_t, char16_t and char32_t are integral types but are - // neither signed integer types nor unsigned integer types, so must be - // transformed to the unsigned integer type with the smallest rank. - // Use the partial specialization for enumeration types to do that. -#if defined(_GLIBCXX_USE_WCHAR_T) - template <> - struct __make_unsigned { - using __type = - typename __make_unsigned_selector::__type; - }; -#endif - -#ifdef _GLIBCXX_USE_CHAR8_T - template <> - struct __make_unsigned { - using __type = - typename __make_unsigned_selector::__type; - }; -#endif - - template <> - struct __make_unsigned { - using __type = - typename __make_unsigned_selector::__type; - }; - - template <> - struct __make_unsigned { - using __type = - typename __make_unsigned_selector::__type; - }; - - // Given an integral/enum type, return the corresponding unsigned - // integer type. - // Primary template. - /// make_unsigned - template - struct make_unsigned { - typedef typename __make_unsigned_selector<_Tp>::__type type; - }; - - // Integral, but don't define. - template <> - struct make_unsigned; - - // Utility for finding the signed versions of unsigned integral types. - template - struct __make_signed { - typedef _Tp __type; - }; - - template <> - struct __make_signed { - typedef signed char __type; - }; - - template <> - struct __make_signed { - typedef signed char __type; - }; - - template <> - struct __make_signed { - typedef signed short __type; - }; - - template <> - struct __make_signed { - typedef signed int __type; - }; - - template <> - struct __make_signed { - typedef signed long __type; - }; - - template <> - struct __make_signed { - typedef signed long long __type; - }; - -#if defined(__GLIBCXX_TYPE_INT_N_0) - template <> - struct __make_signed { - typedef __GLIBCXX_TYPE_INT_N_0 __type; - }; -#endif -#if defined(__GLIBCXX_TYPE_INT_N_1) - template <> - struct __make_signed { - typedef __GLIBCXX_TYPE_INT_N_1 __type; - }; -#endif -#if defined(__GLIBCXX_TYPE_INT_N_2) - template <> - struct __make_signed { - typedef __GLIBCXX_TYPE_INT_N_2 __type; - }; -#endif -#if defined(__GLIBCXX_TYPE_INT_N_3) - template <> - struct __make_signed { - typedef __GLIBCXX_TYPE_INT_N_3 __type; - }; -#endif - - // Select between integral and enum: not possible to be both. - template ::value, - bool _IsEnum = is_enum<_Tp>::value> - class __make_signed_selector; - - template - class __make_signed_selector<_Tp, true, false> { - using __signed_type = - typename __make_signed<__remove_cv_t<_Tp>>::__type; - - public: - using __type = - typename __match_cv_qualifiers<_Tp, __signed_type>::__type; - }; - - // Choose signed integer type with the smallest rank and same size as _Tp - template - class __make_signed_selector<_Tp, false, true> { - typedef typename __make_unsigned_selector<_Tp>::__type __unsigned_type; - - public: - typedef typename __make_signed_selector<__unsigned_type>::__type __type; - }; - - // int, char16_t and char32_t are integral types but are neither - // signed integer types nor unsigned integer types, so must be - // transformed to the signed integer type with the smallest rank. - // Use the partial specialization for enumeration types to do that. -#if defined(_GLIBCXX_USE_WCHAR_T) - template <> - struct __make_signed { - using __type = - typename __make_signed_selector::__type; - }; -#endif - -#if defined(_GLIBCXX_USE_CHAR8_T) - template <> - struct __make_signed { - using __type = - typename __make_signed_selector::__type; - }; -#endif - - template <> - struct __make_signed { - using __type = - typename __make_signed_selector::__type; - }; - - template <> - struct __make_signed { - using __type = - typename __make_signed_selector::__type; - }; - - // Given an integral/enum type, return the corresponding signed - // integer type. - // Primary template. - /// make_signed - template - struct make_signed { - typedef typename __make_signed_selector<_Tp>::__type type; - }; - - // Integral, but don't define. - template <> - struct make_signed; - -#if __cplusplus > 201103L - /// Alias template for make_signed - template - using make_signed_t = typename make_signed<_Tp>::type; - - /// Alias template for make_unsigned - template - using make_unsigned_t = typename make_unsigned<_Tp>::type; -#endif - - // Array modifications. - - /// remove_extent - template - struct remove_extent { - typedef _Tp type; - }; - - template - struct remove_extent<_Tp[_Size]> { - typedef _Tp type; - }; - - template - struct remove_extent<_Tp[]> { - typedef _Tp type; - }; - - /// remove_all_extents - template - struct remove_all_extents { - typedef _Tp type; - }; - - template - struct remove_all_extents<_Tp[_Size]> { - typedef typename remove_all_extents<_Tp>::type type; - }; - - template - struct remove_all_extents<_Tp[]> { - typedef typename remove_all_extents<_Tp>::type type; - }; - -#if __cplusplus > 201103L - /// Alias template for remove_extent - template - using remove_extent_t = typename remove_extent<_Tp>::type; - - /// Alias template for remove_all_extents - template - using remove_all_extents_t = typename remove_all_extents<_Tp>::type; -#endif - - // Pointer modifications. - - template - struct __remove_pointer_helper { - typedef _Tp type; - }; - - template - struct __remove_pointer_helper<_Tp, _Up *> { - typedef _Up type; - }; - - /// remove_pointer - template - struct remove_pointer - : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>> {}; - - /// add_pointer - template , is_void<_Tp>>::value> - struct __add_pointer_helper { - typedef _Tp type; - }; - - template - struct __add_pointer_helper<_Tp, true> { - typedef typename remove_reference<_Tp>::type *type; - }; - - template - struct add_pointer : public __add_pointer_helper<_Tp> {}; - -#if __cplusplus > 201103L - /// Alias template for remove_pointer - template - using remove_pointer_t = typename remove_pointer<_Tp>::type; - - /// Alias template for add_pointer - template - using add_pointer_t = typename add_pointer<_Tp>::type; -#endif - - template - struct __aligned_storage_msa { - union __type { - unsigned char __data[_Len]; - struct __attribute__((__aligned__)) { - } __align; - }; - }; - - /** - * @brief Alignment type. - * - * The value of _Align is a default-alignment which shall be the - * most stringent alignment requirement for any C++ object type - * whose size is no greater than _Len (3.9). The member typedef - * type shall be a POD type suitable for use as uninitialized - * storage for any object whose size is at most _Len and whose - * alignment is a divisor of _Align. - */ - template ::__type)> - struct aligned_storage { - union type { - unsigned char __data[_Len]; - struct __attribute__((__aligned__((_Align)))) { - } __align; - }; - }; - - template - struct __strictest_alignment { - static const size_t _S_alignment = 0; - static const size_t _S_size = 0; - }; - - template - struct __strictest_alignment<_Tp, _Types...> { - static const size_t _S_alignment = - alignof(_Tp) > __strictest_alignment<_Types...>::_S_alignment - ? alignof(_Tp) - : __strictest_alignment<_Types...>::_S_alignment; - static const size_t - _S_size = sizeof(_Tp) > __strictest_alignment<_Types...>::_S_size - ? sizeof(_Tp) - : __strictest_alignment<_Types...>::_S_size; - }; - - /** - * @brief Provide aligned storage for types. - * - * [meta.trans.other] - * - * Provides aligned storage for any of the provided types of at - * least size _Len. - * - * @see aligned_storage - */ - template - struct aligned_union { - private: - static_assert(sizeof...(_Types) != 0, "At least one type is required"); - - using __strictest = __strictest_alignment<_Types...>; - static const size_t _S_len = - _Len > __strictest::_S_size ? _Len : __strictest::_S_size; - - public: - /// The value of the strictest alignment of _Types. - static const size_t alignment_value = __strictest::_S_alignment; - /// The storage. - typedef typename aligned_storage<_S_len, alignment_value>::type type; - }; - - template - const size_t aligned_union<_Len, _Types...>::alignment_value; - - // Decay trait for arrays and functions, used for perfect forwarding - // in make_pair, make_tuple, etc. - template ::value, - bool _IsFunction = is_function<_Up>::value> - struct __decay_selector; - - // NB: DR 705. - template - struct __decay_selector<_Up, false, false> { - typedef __remove_cv_t<_Up> __type; - }; - - template - struct __decay_selector<_Up, true, false> { - typedef typename remove_extent<_Up>::type *__type; - }; - - template - struct __decay_selector<_Up, false, true> { - typedef typename add_pointer<_Up>::type __type; - }; - - /// decay - template - class decay { - typedef typename remove_reference<_Tp>::type __remove_type; - - public: - typedef typename __decay_selector<__remove_type>::__type type; - }; - - // __decay_t (std::decay_t for C++11). - template - using __decay_t = typename decay<_Tp>::type; - - template - class reference_wrapper; - - // Helper which adds a reference to a type when given a reference_wrapper - template - struct __strip_reference_wrapper { - typedef _Tp __type; - }; - - template - struct __strip_reference_wrapper> { - typedef _Tp &__type; - }; - - template - using __decay_and_strip = __strip_reference_wrapper<__decay_t<_Tp>>; - - // Primary template. - /// Define a member typedef @c type only if a boolean constant is true. - template - struct enable_if {}; - - // Partial specialization for true. - template - struct enable_if { - typedef _Tp type; - }; - - // __enable_if_t (std::enable_if_t for C++11) - template - using __enable_if_t = typename enable_if<_Cond, _Tp>::type; - - template - using _Require = __enable_if_t<__and_<_Cond...>::value>; - - // Primary template. - /// Define a member typedef @c type to one of two argument types. - template - struct conditional { - typedef _Iftrue type; - }; - - // Partial specialization for false. - template - struct conditional { - typedef _Iffalse type; - }; - - // __remove_cvref_t (std::remove_cvref_t for C++11). - template - using __remove_cvref_t = - typename remove_cv::type>::type; - - /// common_type - template - struct common_type; - - // Sfinae-friendly common_type implementation: - - struct __do_common_type_impl { - template - using __cond_t = - decltype(true ? std::declval<_Tp>() : std::declval<_Up>()); - - // if decay_t() : declval())> - // denotes a valid type, let C denote that type. - template - static __success_type<__decay_t<__cond_t<_Tp, _Up>>> _S_test(int); - -#if __cplusplus > 201703L - // Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, - // let C denote the type decay_t. - template - static __success_type< - __remove_cvref_t<__cond_t>> - _S_test_2(int); -#endif - - template - static __failure_type _S_test_2(...); - - template - static decltype(_S_test_2<_Tp, _Up>(0)) _S_test(...); - }; - - // If sizeof...(T) is zero, there shall be no member type. - template <> - struct common_type<> {}; - - // If sizeof...(T) is one, the same type, if any, as common_type_t. - template - struct common_type<_Tp0> : public common_type<_Tp0, _Tp0> {}; - - // If sizeof...(T) is two, ... - template , - typename _Dp2 = __decay_t<_Tp2>> - struct __common_type_impl { - // If is_same_v is false or is_same_v is false, - // let C denote the same type, if any, as common_type_t. - using type = common_type<_Dp1, _Dp2>; - }; - - template - struct __common_type_impl<_Tp1, _Tp2, _Tp1, _Tp2> - : private __do_common_type_impl { - // Otherwise, if decay_t() : - // declval())> denotes a valid type, let C denote that type. - using type = decltype(_S_test<_Tp1, _Tp2>(0)); - }; - - // If sizeof...(T) is two, ... - template - struct common_type<_Tp1, _Tp2> - : public __common_type_impl<_Tp1, _Tp2>::type {}; - - template - struct __common_type_pack {}; - - template - struct __common_type_fold; - - // If sizeof...(T) is greater than two, ... - template - struct common_type<_Tp1, _Tp2, _Rp...> - : public __common_type_fold, - __common_type_pack<_Rp...>> {}; - - // Let C denote the same type, if any, as common_type_t. - // If there is such a type C, type shall denote the same type, if any, - // as common_type_t. - template - struct __common_type_fold<_CTp, __common_type_pack<_Rp...>, - __void_t> - : public common_type {}; - - // Otherwise, there shall be no member type. - template - struct __common_type_fold<_CTp, _Rp, void> {}; - - template ::value> - struct __underlying_type_impl { - using type = __underlying_type(_Tp); - }; - - template - struct __underlying_type_impl<_Tp, false> {}; - - /// The underlying type of an enum. - template - struct underlying_type : public __underlying_type_impl<_Tp> {}; - - template - struct __declval_protector { - static const bool __stop = false; - }; - - template - auto declval() noexcept -> decltype(__declval<_Tp>(0)) { - static_assert(__declval_protector<_Tp>::__stop, - "declval() must not be used!"); - return __declval<_Tp>(0); - } + template + static decltype(_S_test_2<_Tp, _Up>(0)) _S_test(...); +}; + +// If sizeof...(T) is zero, there shall be no member type. +template <> +struct common_type<> { }; + +// If sizeof...(T) is one, the same type, if any, as common_type_t. +template +struct common_type<_Tp0> : public common_type<_Tp0, _Tp0> { }; + +// If sizeof...(T) is two, ... +template , + typename _Dp2 = __decay_t<_Tp2>> +struct __common_type_impl { + // If is_same_v is false or is_same_v is false, + // let C denote the same type, if any, as common_type_t. + using type = common_type<_Dp1, _Dp2>; +}; + +template +struct __common_type_impl<_Tp1, _Tp2, _Tp1, _Tp2> + : private __do_common_type_impl { + // Otherwise, if decay_t() : + // declval())> denotes a valid type, let C denote that type. + using type = decltype(_S_test<_Tp1, _Tp2>(0)); +}; + +// If sizeof...(T) is two, ... +template +struct common_type<_Tp1, _Tp2> : public __common_type_impl<_Tp1, _Tp2>::type { +}; + +template +struct __common_type_pack { }; + +template +struct __common_type_fold; + +// If sizeof...(T) is greater than two, ... +template +struct common_type<_Tp1, _Tp2, _Rp...> + : public __common_type_fold, + __common_type_pack<_Rp...>> { }; + +// Let C denote the same type, if any, as common_type_t. +// If there is such a type C, type shall denote the same type, if any, +// as common_type_t. +template +struct __common_type_fold<_CTp, __common_type_pack<_Rp...>, + __void_t> + : public common_type { }; + +// Otherwise, there shall be no member type. +template +struct __common_type_fold<_CTp, _Rp, void> { }; + +template ::value> +struct __underlying_type_impl { + using type = __underlying_type(_Tp); +}; + +template +struct __underlying_type_impl<_Tp, false> { }; + +/// The underlying type of an enum. +template +struct underlying_type : public __underlying_type_impl<_Tp> { }; + +template +struct __declval_protector { + static const bool __stop = false; +}; + +template +auto declval() noexcept -> decltype(__declval<_Tp>(0)) { + static_assert(__declval_protector<_Tp>::__stop, + "declval() must not be used!"); + return __declval<_Tp>(0); +} - /// result_of - template - class result_of; +/// result_of +template +class result_of; - // Sfinae-friendly result_of implementation: +// Sfinae-friendly result_of implementation: #define __cpp_lib_result_of_sfinae 201210 - struct __invoke_memfun_ref {}; - struct __invoke_memfun_deref {}; - struct __invoke_memobj_ref {}; - struct __invoke_memobj_deref {}; - struct __invoke_other {}; - - // Associate a tag type with a specialization of __success_type. - template - struct __result_of_success : __success_type<_Tp> { - using __invoke_type = _Tag; - }; - - // [func.require] paragraph 1 bullet 1: - struct __result_of_memfun_ref_impl { - template - static __result_of_success< - decltype((std::declval<_Tp1>().* - std::declval<_Fp>())(std::declval<_Args>()...)), - __invoke_memfun_ref> - _S_test(int); - - template - static __failure_type _S_test(...); - }; - - template - struct __result_of_memfun_ref : private __result_of_memfun_ref_impl { - typedef decltype(_S_test<_MemPtr, _Arg, _Args...>(0)) type; - }; - - // [func.require] paragraph 1 bullet 2: - struct __result_of_memfun_deref_impl { - template - static __result_of_success< - decltype(((*std::declval<_Tp1>()).* - std::declval<_Fp>())(std::declval<_Args>()...)), - __invoke_memfun_deref> - _S_test(int); - - template - static __failure_type _S_test(...); - }; - - template - struct __result_of_memfun_deref : private __result_of_memfun_deref_impl { - typedef decltype(_S_test<_MemPtr, _Arg, _Args...>(0)) type; - }; - - // [func.require] paragraph 1 bullet 3: - struct __result_of_memobj_ref_impl { - template - static __result_of_success().* - std::declval<_Fp>()), - __invoke_memobj_ref> - _S_test(int); - - template - static __failure_type _S_test(...); - }; - - template - struct __result_of_memobj_ref : private __result_of_memobj_ref_impl { - typedef decltype(_S_test<_MemPtr, _Arg>(0)) type; - }; - - // [func.require] paragraph 1 bullet 4: - struct __result_of_memobj_deref_impl { - template - static __result_of_success()).* - std::declval<_Fp>()), - __invoke_memobj_deref> - _S_test(int); - - template - static __failure_type _S_test(...); - }; - - template - struct __result_of_memobj_deref : private __result_of_memobj_deref_impl { - typedef decltype(_S_test<_MemPtr, _Arg>(0)) type; - }; +struct __invoke_memfun_ref { }; - template - struct __result_of_memobj; - - template - struct __result_of_memobj<_Res _Class::*, _Arg> { - typedef __remove_cvref_t<_Arg> _Argval; - typedef _Res _Class::*_MemPtr; - typedef typename conditional< - __or_, is_base_of<_Class, _Argval>>::value, - __result_of_memobj_ref<_MemPtr, _Arg>, - __result_of_memobj_deref<_MemPtr, _Arg>>::type::type type; - }; +struct __invoke_memfun_deref { }; - template - struct __result_of_memfun; - - template - struct __result_of_memfun<_Res _Class::*, _Arg, _Args...> { - typedef typename remove_reference<_Arg>::type _Argval; - typedef _Res _Class::*_MemPtr; - typedef typename conditional< - is_base_of<_Class, _Argval>::value, - __result_of_memfun_ref<_MemPtr, _Arg, _Args...>, - __result_of_memfun_deref<_MemPtr, _Arg, _Args...>>::type::type type; - }; +struct __invoke_memobj_ref { }; - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2219. INVOKE-ing a pointer to member with a reference_wrapper - // as the object expression +struct __invoke_memobj_deref { }; - // Used by result_of, invoke etc. to unwrap a reference_wrapper. - template > - struct __inv_unwrap { - using type = _Tp; - }; +struct __invoke_other { }; - template - struct __inv_unwrap<_Tp, reference_wrapper<_Up>> { - using type = _Up &; - }; +// Associate a tag type with a specialization of __success_type. +template +struct __result_of_success : __success_type<_Tp> { + using __invoke_type = _Tag; +}; - template - struct __result_of_impl { - typedef __failure_type type; - }; +// [func.require] paragraph 1 bullet 1: +struct __result_of_memfun_ref_impl { + template + static __result_of_success< + decltype((std::declval<_Tp1>() + .*std::declval<_Fp>())(std::declval<_Args>()...)), + __invoke_memfun_ref> + _S_test(int); - template - struct __result_of_impl - : public __result_of_memobj<__decay_t<_MemPtr>, - typename __inv_unwrap<_Arg>::type> {}; + template + static __failure_type _S_test(...); +}; + +template +struct __result_of_memfun_ref : private __result_of_memfun_ref_impl { + typedef decltype(_S_test<_MemPtr, _Arg, _Args...>(0)) type; +}; + +// [func.require] paragraph 1 bullet 2: +struct __result_of_memfun_deref_impl { + template + static __result_of_success< + decltype(((*std::declval<_Tp1>()) + .*std::declval<_Fp>())(std::declval<_Args>()...)), + __invoke_memfun_deref> + _S_test(int); - template - struct __result_of_impl - : public __result_of_memfun< - __decay_t<_MemPtr>, typename __inv_unwrap<_Arg>::type, _Args...> { - }; + template + static __failure_type _S_test(...); +}; - // [func.require] paragraph 1 bullet 5: - struct __result_of_other_impl { - template - static __result_of_success< - decltype(std::declval<_Fn>()(std::declval<_Args>()...)), - __invoke_other> - _S_test(int); +template +struct __result_of_memfun_deref : private __result_of_memfun_deref_impl { + typedef decltype(_S_test<_MemPtr, _Arg, _Args...>(0)) type; +}; - template - static __failure_type _S_test(...); - }; +// [func.require] paragraph 1 bullet 3: +struct __result_of_memobj_ref_impl { + template + static __result_of_success< + decltype(std::declval<_Tp1>().*std::declval<_Fp>()), __invoke_memobj_ref> + _S_test(int); - template - struct __result_of_impl - : private __result_of_other_impl { - typedef decltype(_S_test<_Functor, _ArgTypes...>(0)) type; - }; + template + static __failure_type _S_test(...); +}; + +template +struct __result_of_memobj_ref : private __result_of_memobj_ref_impl { + typedef decltype(_S_test<_MemPtr, _Arg>(0)) type; +}; + +// [func.require] paragraph 1 bullet 4: +struct __result_of_memobj_deref_impl { + template + static __result_of_success()) + .*std::declval<_Fp>()), + __invoke_memobj_deref> + _S_test(int); - // __invoke_result (std::invoke_result for C++11) - template - struct __invoke_result - : public __result_of_impl< - is_member_object_pointer< - typename remove_reference<_Functor>::type>::value, - is_member_function_pointer< - typename remove_reference<_Functor>::type>::value, - _Functor, _ArgTypes...>::type {}; + template + static __failure_type _S_test(...); +}; + +template +struct __result_of_memobj_deref : private __result_of_memobj_deref_impl { + typedef decltype(_S_test<_MemPtr, _Arg>(0)) type; +}; + +template +struct __result_of_memobj; + +template +struct __result_of_memobj<_Res _Class::*, _Arg> { + typedef __remove_cvref_t<_Arg> _Argval; + typedef _Res _Class::*_MemPtr; + typedef typename conditional< + __or_, is_base_of<_Class, _Argval>>::value, + __result_of_memobj_ref<_MemPtr, _Arg>, + __result_of_memobj_deref<_MemPtr, _Arg>>::type::type type; +}; + +template +struct __result_of_memfun; + +template +struct __result_of_memfun<_Res _Class::*, _Arg, _Args...> { + typedef typename remove_reference<_Arg>::type _Argval; + typedef _Res _Class::*_MemPtr; + typedef typename conditional< + is_base_of<_Class, _Argval>::value, + __result_of_memfun_ref<_MemPtr, _Arg, _Args...>, + __result_of_memfun_deref<_MemPtr, _Arg, _Args...>>::type::type type; +}; + +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// 2219. INVOKE-ing a pointer to member with a reference_wrapper +// as the object expression + +// Used by result_of, invoke etc. to unwrap a reference_wrapper. +template > +struct __inv_unwrap { + using type = _Tp; +}; + +template +struct __inv_unwrap<_Tp, reference_wrapper<_Up>> { + using type = _Up&; +}; + +template +struct __result_of_impl { + typedef __failure_type type; +}; + +template +struct __result_of_impl + : public __result_of_memobj<__decay_t<_MemPtr>, + typename __inv_unwrap<_Arg>::type> { }; + +template +struct __result_of_impl + : public __result_of_memfun<__decay_t<_MemPtr>, + typename __inv_unwrap<_Arg>::type, _Args...> { +}; + +// [func.require] paragraph 1 bullet 5: +struct __result_of_other_impl { + template + static __result_of_success< + decltype(std::declval<_Fn>()(std::declval<_Args>()...)), __invoke_other> + _S_test(int); - template - struct result_of<_Functor(_ArgTypes...)> - : public __invoke_result<_Functor, _ArgTypes...> {}; + template + static __failure_type _S_test(...); +}; + +template +struct __result_of_impl + : private __result_of_other_impl { + typedef decltype(_S_test<_Functor, _ArgTypes...>(0)) type; +}; + +// __invoke_result (std::invoke_result for C++11) +template +struct __invoke_result : public __result_of_impl< + is_member_object_pointer< + typename remove_reference<_Functor>::type>::value, + is_member_function_pointer< + typename remove_reference<_Functor>::type>::value, + _Functor, _ArgTypes...>::type { }; + +template +struct result_of<_Functor(_ArgTypes...)> + : public __invoke_result<_Functor, _ArgTypes...> { }; #if __cplusplus >= 201402L - /// Alias template for aligned_storage - template ::__type)> - using aligned_storage_t = typename aligned_storage<_Len, _Align>::type; - - template - using aligned_union_t = typename aligned_union<_Len, _Types...>::type; - - /// Alias template for decay - template - using decay_t = typename decay<_Tp>::type; - - /// Alias template for enable_if - template - using enable_if_t = typename enable_if<_Cond, _Tp>::type; - - /// Alias template for conditional - template - using conditional_t = typename conditional<_Cond, _Iftrue, _Iffalse>::type; - - /// Alias template for common_type - template - using common_type_t = typename common_type<_Tp...>::type; - - /// Alias template for underlying_type - template - using underlying_type_t = typename underlying_type<_Tp>::type; - - /// Alias template for result_of - template - using result_of_t = typename result_of<_Tp>::type; -#endif // C++14 - -#if __cplusplus >= 201703L || !defined(__STRICT_ANSI__) // c++17 or gnu++11 -#define __cpp_lib_void_t 201411 - /// A metafunction that always yields void, used for detecting valid types. - template - using void_t = void; +/// Alias template for aligned_storage +template ::__type)> +using aligned_storage_t = typename aligned_storage<_Len, _Align>::type; + +template +using aligned_union_t = typename aligned_union<_Len, _Types...>::type; + +/// Alias template for decay +template +using decay_t = typename decay<_Tp>::type; + +/// Alias template for enable_if +template +using enable_if_t = typename enable_if<_Cond, _Tp>::type; + +/// Alias template for conditional +template +using conditional_t = typename conditional<_Cond, _Iftrue, _Iffalse>::type; + +/// Alias template for common_type +template +using common_type_t = typename common_type<_Tp...>::type; + +/// Alias template for underlying_type +template +using underlying_type_t = typename underlying_type<_Tp>::type; + +/// Alias template for result_of +template +using result_of_t = typename result_of<_Tp>::type; +#endif // C++14 + +#if __cplusplus >= 201703L || !defined(__STRICT_ANSI__) // c++17 or gnu++11 +# define __cpp_lib_void_t 201411 +/// A metafunction that always yields void, used for detecting valid types. +template +using void_t = void; #endif - /// Implementation of the detection idiom (negative case). - template class _Op, typename... _Args> - struct __detector { - using value_t = false_type; - using type = _Default; - }; - - /// Implementation of the detection idiom (positive case). - template class _Op, - typename... _Args> - struct __detector<_Default, __void_t<_Op<_Args...>>, _Op, _Args...> { - using value_t = true_type; - using type = _Op<_Args...>; - }; - - // Detect whether _Op<_Args...> is a valid type, use _Default if not. - template class _Op, - typename... _Args> - using __detected_or = __detector<_Default, void, _Op, _Args...>; - - // _Op<_Args...> if that is a valid type, otherwise _Default. - template class _Op, - typename... _Args> - using __detected_or_t = - typename __detected_or<_Default, _Op, _Args...>::type; - - /// @} group metaprogramming - - /** - * Use SFINAE to determine if the type _Tp has a publicly-accessible - * member type _NTYPE. - */ -#define _GLIBCXX_HAS_NESTED_TYPE(_NTYPE) \ - template > \ - struct __has_##_NTYPE : false_type {}; \ - template \ - struct __has_##_NTYPE<_Tp, __void_t> : true_type {}; - - template - struct __is_swappable; - - template - struct __is_nothrow_swappable; - - template - class tuple; +/// Implementation of the detection idiom (negative case). +template class _Op, typename... _Args> +struct __detector { + using value_t = false_type; + using type = _Default; +}; + +/// Implementation of the detection idiom (positive case). +template class _Op, + typename... _Args> +struct __detector<_Default, __void_t<_Op<_Args...>>, _Op, _Args...> { + using value_t = true_type; + using type = _Op<_Args...>; +}; + +// Detect whether _Op<_Args...> is a valid type, use _Default if not. +template class _Op, + typename... _Args> +using __detected_or = __detector<_Default, void, _Op, _Args...>; + +// _Op<_Args...> if that is a valid type, otherwise _Default. +template class _Op, + typename... _Args> +using __detected_or_t = typename __detected_or<_Default, _Op, _Args...>::type; + +/// @} group metaprogramming + +/** + * Use SFINAE to determine if the type _Tp has a publicly-accessible + * member type _NTYPE. + */ +#define _GLIBCXX_HAS_NESTED_TYPE(_NTYPE) \ + template > \ + struct __has_##_NTYPE : false_type { }; \ + template \ + struct __has_##_NTYPE<_Tp, __void_t> : true_type { \ + }; + +template +struct __is_swappable; + +template +struct __is_nothrow_swappable; + +template +class tuple; + +template +struct __is_tuple_like_impl : false_type { }; + +template +struct __is_tuple_like_impl> : true_type { }; + +// Internal type trait that allows us to sfinae-protect tuple_cat. +template +struct __is_tuple_like + : public __is_tuple_like_impl<__remove_cvref_t<_Tp>>::type { }; + +template +constexpr inline _Require<__not_<__is_tuple_like<_Tp>>, + is_move_constructible<_Tp>, is_move_assignable<_Tp>> +swap(_Tp&, _Tp&) noexcept(__and_, + is_nothrow_move_assignable<_Tp>>::value); + +template +constexpr inline __enable_if_t<__is_swappable<_Tp>::value> + swap(_Tp (&__a)[_Nm], + _Tp (&__b)[_Nm]) noexcept(__is_nothrow_swappable<_Tp>::value); + +namespace __swappable_details { +using std::swap; + +struct __do_is_swappable_impl { + template (), + std::declval<_Tp&>()))> + static true_type __test(int); template - struct __is_tuple_like_impl : false_type {}; - - template - struct __is_tuple_like_impl> : true_type {}; - - // Internal type trait that allows us to sfinae-protect tuple_cat. - template - struct __is_tuple_like - : public __is_tuple_like_impl<__remove_cvref_t<_Tp>>::type {}; + static false_type __test(...); +}; +struct __do_is_nothrow_swappable_impl { template - constexpr inline _Require<__not_<__is_tuple_like<_Tp>>, - is_move_constructible<_Tp>, - is_move_assignable<_Tp>> - swap(_Tp &, _Tp &) noexcept(__and_, - is_nothrow_move_assignable<_Tp>>::value); - - template - constexpr inline __enable_if_t<__is_swappable<_Tp>::value> - swap(_Tp (&__a)[_Nm], - _Tp (&__b)[_Nm]) noexcept(__is_nothrow_swappable<_Tp>::value); - - namespace __swappable_details { - using std::swap; - - struct __do_is_swappable_impl { - template (), - std::declval<_Tp &>()))> - static true_type __test(int); - - template - static false_type __test(...); - }; - - struct __do_is_nothrow_swappable_impl { - template - static __bool_constant(), - std::declval<_Tp &>()))> - __test(int); - - template - static false_type __test(...); - }; - - } // namespace __swappable_details + static __bool_constant(), + std::declval<_Tp&>()))> + __test(int); - template - struct __is_swappable_impl - : public __swappable_details::__do_is_swappable_impl { - typedef decltype(__test<_Tp>(0)) type; - }; + template + static false_type __test(...); +}; + +} // namespace __swappable_details + +template +struct __is_swappable_impl + : public __swappable_details::__do_is_swappable_impl { + typedef decltype(__test<_Tp>(0)) type; +}; + +template +struct __is_nothrow_swappable_impl + : public __swappable_details::__do_is_nothrow_swappable_impl { + typedef decltype(__test<_Tp>(0)) type; +}; + +template +struct __is_swappable : public __is_swappable_impl<_Tp>::type { }; + +template +struct __is_nothrow_swappable : public __is_nothrow_swappable_impl<_Tp>::type { +}; + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 +# define __cpp_lib_is_swappable 201603 + +/// Metafunctions used for detecting swappable types: p0185r1 + +/// is_swappable +template +struct is_swappable : public __is_swappable_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +/// is_nothrow_swappable +template +struct is_nothrow_swappable : public __is_nothrow_swappable_impl<_Tp>::type { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +# if __cplusplus >= 201402L +/// is_swappable_v +template +inline constexpr bool is_swappable_v = is_swappable<_Tp>::value; + +/// is_nothrow_swappable_v +template +inline constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<_Tp>::value; +# endif // __cplusplus >= 201402L + +namespace __swappable_with_details { +using std::swap; + +struct __do_is_swappable_with_impl { + template < + typename _Tp, typename _Up, + typename = decltype(swap(std::declval<_Tp>(), std::declval<_Up>())), + typename = decltype(swap(std::declval<_Up>(), std::declval<_Tp>()))> + static true_type __test(int); - template - struct __is_nothrow_swappable_impl - : public __swappable_details::__do_is_nothrow_swappable_impl { - typedef decltype(__test<_Tp>(0)) type; - }; + template + static false_type __test(...); +}; - template - struct __is_swappable : public __is_swappable_impl<_Tp>::type {}; +struct __do_is_nothrow_swappable_with_impl { + template + static __bool_constant< + noexcept(swap(std::declval<_Tp>(), std::declval<_Up>())) + && noexcept(swap(std::declval<_Up>(), std::declval<_Tp>()))> + __test(int); - template - struct __is_nothrow_swappable - : public __is_nothrow_swappable_impl<_Tp>::type {}; + template + static false_type __test(...); +}; + +} // namespace __swappable_with_details + +template +struct __is_swappable_with_impl + : public __swappable_with_details::__do_is_swappable_with_impl { + typedef decltype(__test<_Tp, _Up>(0)) type; +}; + +// Optimization for the homogenous lvalue case, not required: +template +struct __is_swappable_with_impl<_Tp&, _Tp&> + : public __swappable_details::__do_is_swappable_impl { + typedef decltype(__test<_Tp&>(0)) type; +}; + +template +struct __is_nothrow_swappable_with_impl + : public __swappable_with_details::__do_is_nothrow_swappable_with_impl { + typedef decltype(__test<_Tp, _Up>(0)) type; +}; + +// Optimization for the homogenous lvalue case, not required: +template +struct __is_nothrow_swappable_with_impl<_Tp&, _Tp&> + : public __swappable_details::__do_is_nothrow_swappable_impl { + typedef decltype(__test<_Tp&>(0)) type; +}; + +/// is_swappable_with +template +struct is_swappable_with : public __is_swappable_with_impl<_Tp, _Up>::type { }; + +/// is_nothrow_swappable_with +template +struct is_nothrow_swappable_with + : public __is_nothrow_swappable_with_impl<_Tp, _Up>::type { }; + +# if __cplusplus >= 201402L +/// is_swappable_with_v +template +inline constexpr bool is_swappable_with_v = is_swappable_with<_Tp, _Up>::value; + +/// is_nothrow_swappable_with_v +template +inline constexpr bool is_nothrow_swappable_with_v + = is_nothrow_swappable_with<_Tp, _Up>::value; +# endif // __cplusplus >= 201402L + +#endif // c++1z or gnu++11 + +// __is_invocable (std::is_invocable for C++11) + +// The primary template is used for invalid INVOKE expressions. +template ::value, + typename = void> +struct __is_invocable_impl : false_type { }; + +// Used for valid INVOKE and INVOKE expressions. +template +struct __is_invocable_impl<_Result, _Ret, + /* is_void<_Ret> = */ true, + __void_t> : true_type { }; -#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 -#define __cpp_lib_is_swappable 201603 - /// Metafunctions used for detecting swappable types: p0185r1 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" - /// is_swappable - template - struct is_swappable : public __is_swappable_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; +// Used for INVOKE expressions to check the implicit conversion to R. +template +struct __is_invocable_impl<_Result, _Ret, + /* is_void<_Ret> = */ false, + __void_t> { +private: + // The type of the INVOKE expression. + // Unlike declval, this doesn't add_rvalue_reference. + static typename _Result::type _S_get(); - /// is_nothrow_swappable template - struct is_nothrow_swappable - : public __is_nothrow_swappable_impl<_Tp>::type { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; + static void _S_conv(_Tp); -#if __cplusplus >= 201402L - /// is_swappable_v - template - inline constexpr bool is_swappable_v = is_swappable<_Tp>::value; + // This overload is viable if INVOKE(f, args...) can convert to _Tp. + template (_S_get()))> + static true_type _S_test(int); - /// is_nothrow_swappable_v template - inline constexpr bool is_nothrow_swappable_v = - is_nothrow_swappable<_Tp>::value; -#endif // __cplusplus >= 201402L - - namespace __swappable_with_details { - using std::swap; - - struct __do_is_swappable_with_impl { - template (), - std::declval<_Up>())), - typename = decltype(swap(std::declval<_Up>(), - std::declval<_Tp>()))> - static true_type __test(int); - - template - static false_type __test(...); - }; - - struct __do_is_nothrow_swappable_with_impl { - template - static __bool_constant< - noexcept(swap(std::declval<_Tp>(), std::declval<_Up>())) - &&noexcept(swap(std::declval<_Up>(), std::declval<_Tp>()))> - __test(int); - - template - static false_type __test(...); - }; - - } // namespace __swappable_with_details + static false_type _S_test(...); - template - struct __is_swappable_with_impl - : public __swappable_with_details::__do_is_swappable_with_impl { - typedef decltype(__test<_Tp, _Up>(0)) type; - }; - - // Optimization for the homogenous lvalue case, not required: - template - struct __is_swappable_with_impl<_Tp &, _Tp &> - : public __swappable_details::__do_is_swappable_impl { - typedef decltype(__test<_Tp &>(0)) type; - }; +public: + using type = decltype(_S_test<_Ret>(1)); +}; - template - struct __is_nothrow_swappable_with_impl - : public __swappable_with_details::__do_is_nothrow_swappable_with_impl { - typedef decltype(__test<_Tp, _Up>(0)) type; - }; +#pragma GCC diagnostic pop - // Optimization for the homogenous lvalue case, not required: - template - struct __is_nothrow_swappable_with_impl<_Tp &, _Tp &> - : public __swappable_details::__do_is_nothrow_swappable_impl { - typedef decltype(__test<_Tp &>(0)) type; - }; +template +struct __is_invocable + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type { }; - /// is_swappable_with - template - struct is_swappable_with : public __is_swappable_with_impl<_Tp, _Up>::type { - }; +template +constexpr bool __call_is_nt(__invoke_memfun_ref) { + using _Up = typename __inv_unwrap<_Tp>::type; + return noexcept((std::declval<_Up>() + .*std::declval<_Fn>())(std::declval<_Args>()...)); +} - /// is_nothrow_swappable_with - template - struct is_nothrow_swappable_with - : public __is_nothrow_swappable_with_impl<_Tp, _Up>::type {}; +template +constexpr bool __call_is_nt(__invoke_memfun_deref) { + return noexcept(((*std::declval<_Tp>()) + .*std::declval<_Fn>())(std::declval<_Args>()...)); +} -#if __cplusplus >= 201402L - /// is_swappable_with_v - template - inline constexpr bool is_swappable_with_v = - is_swappable_with<_Tp, _Up>::value; +template +constexpr bool __call_is_nt(__invoke_memobj_ref) { + using _Up = typename __inv_unwrap<_Tp>::type; + return noexcept(std::declval<_Up>().*std::declval<_Fn>()); +} - /// is_nothrow_swappable_with_v - template - inline constexpr bool is_nothrow_swappable_with_v = - is_nothrow_swappable_with<_Tp, _Up>::value; -#endif // __cplusplus >= 201402L +template +constexpr bool __call_is_nt(__invoke_memobj_deref) { + return noexcept((*std::declval<_Tp>()).*std::declval<_Fn>()); +} -#endif // c++1z or gnu++11 +template +constexpr bool __call_is_nt(__invoke_other) { + return noexcept(std::declval<_Fn>()(std::declval<_Args>()...)); +} - // __is_invocable (std::is_invocable for C++11) +template +struct __call_is_nothrow : __bool_constant( + typename _Result::__invoke_type {})> { }; - // The primary template is used for invalid INVOKE expressions. - template ::value, - typename = void> - struct __is_invocable_impl : false_type {}; +template +using __call_is_nothrow_ + = __call_is_nothrow<__invoke_result<_Fn, _Args...>, _Fn, _Args...>; - // Used for valid INVOKE and INVOKE expressions. - template - struct __is_invocable_impl<_Result, _Ret, - /* is_void<_Ret> = */ true, - __void_t> : true_type {}; +// __is_nothrow_invocable (std::is_nothrow_invocable for C++11) +template +struct __is_nothrow_invocable + : __and_<__is_invocable<_Fn, _Args...>, + __call_is_nothrow_<_Fn, _Args...>>::type { }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wctor-dtor-privacy" - // Used for INVOKE expressions to check the implicit conversion to R. - template - struct __is_invocable_impl<_Result, _Ret, - /* is_void<_Ret> = */ false, - __void_t> { - private: - // The type of the INVOKE expression. - // Unlike declval, this doesn't add_rvalue_reference. - static typename _Result::type _S_get(); - - template - static void _S_conv(_Tp); - - // This overload is viable if INVOKE(f, args...) can convert to _Tp. - template (_S_get()))> - static true_type _S_test(int); - - template - static false_type _S_test(...); - - public: - using type = decltype(_S_test<_Ret>(1)); - }; -#pragma GCC diagnostic pop - - template - struct __is_invocable - : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type { - }; - - template - constexpr bool __call_is_nt(__invoke_memfun_ref) { - using _Up = typename __inv_unwrap<_Tp>::type; - return noexcept((std::declval<_Up>().* - std::declval<_Fn>())(std::declval<_Args>()...)); - } - - template - constexpr bool __call_is_nt(__invoke_memfun_deref) { - return noexcept(((*std::declval<_Tp>()).* - std::declval<_Fn>())(std::declval<_Args>()...)); - } - - template - constexpr bool __call_is_nt(__invoke_memobj_ref) { - using _Up = typename __inv_unwrap<_Tp>::type; - return noexcept(std::declval<_Up>().*std::declval<_Fn>()); - } - - template - constexpr bool __call_is_nt(__invoke_memobj_deref) { - return noexcept((*std::declval<_Tp>()).*std::declval<_Fn>()); - } - - template - constexpr bool __call_is_nt(__invoke_other) { - return noexcept(std::declval<_Fn>()(std::declval<_Args>()...)); - } - template - struct __call_is_nothrow : __bool_constant( - typename _Result::__invoke_type{})> {}; +struct __nonesuchbase { }; - template - using __call_is_nothrow_ = - __call_is_nothrow<__invoke_result<_Fn, _Args...>, _Fn, _Args...>; - - // __is_nothrow_invocable (std::is_nothrow_invocable for C++11) - template - struct __is_nothrow_invocable - : __and_<__is_invocable<_Fn, _Args...>, - __call_is_nothrow_<_Fn, _Args...>>::type {}; +struct __nonesuch : private __nonesuchbase { + ~__nonesuch() = delete; + __nonesuch(const __nonesuch&) = delete; + void operator=(const __nonesuch&) = delete; +}; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" - struct __nonesuchbase {}; - struct __nonesuch : private __nonesuchbase { - ~__nonesuch() = delete; - __nonesuch(__nonesuch const &) = delete; - void operator=(__nonesuch const &) = delete; - }; #pragma GCC diagnostic pop #if __cplusplus >= 201703L -#define __cpp_lib_is_invocable 201703 - - /// std::invoke_result - template - struct invoke_result : public __invoke_result<_Functor, _ArgTypes...> {}; - - /// std::invoke_result_t - template - using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; - - /// std::is_invocable - template - struct is_invocable - : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type { - static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), - "_Fn must be a complete class or an unbounded array"); - }; - - /// std::is_invocable_r - template - struct is_invocable_r - : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>::type { - static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), - "_Fn must be a complete class or an unbounded array"); - }; - - /// std::is_nothrow_invocable - template - struct is_nothrow_invocable - : __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>, - __call_is_nothrow_<_Fn, _ArgTypes...>>::type { - static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), - "_Fn must be a complete class or an unbounded array"); - }; - - template - struct __is_nt_invocable_impl : false_type {}; - - template - struct __is_nt_invocable_impl<_Result, _Ret, - __void_t> - : __or_, - __is_nothrow_convertible> {}; - - /// std::is_nothrow_invocable_r - template - struct is_nothrow_invocable_r - : __and_< - __is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>, - __call_is_nothrow_<_Fn, _ArgTypes...>>::type {}; - - /// std::is_invocable_v - template - inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; - - /// std::is_nothrow_invocable_v - template - inline constexpr bool is_nothrow_invocable_v = - is_nothrow_invocable<_Fn, _Args...>::value; - - /// std::is_invocable_r_v - template - inline constexpr bool is_invocable_r_v = - is_invocable_r<_Ret, _Fn, _Args...>::value; - - /// std::is_nothrow_invocable_r_v - template - inline constexpr bool is_nothrow_invocable_r_v = - is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; -#endif // C++17 +# define __cpp_lib_is_invocable 201703 + +/// std::invoke_result +template +struct invoke_result : public __invoke_result<_Functor, _ArgTypes...> { }; + +/// std::invoke_result_t +template +using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; + +/// std::is_invocable +template +struct is_invocable + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn> {}), + "_Fn must be a complete class or an unbounded array"); +}; + +/// std::is_invocable_r +template +struct is_invocable_r + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>::type { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn> {}), + "_Fn must be a complete class or an unbounded array"); +}; + +/// std::is_nothrow_invocable +template +struct is_nothrow_invocable + : __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>, + __call_is_nothrow_<_Fn, _ArgTypes...>>::type { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn> {}), + "_Fn must be a complete class or an unbounded array"); +}; + +template +struct __is_nt_invocable_impl : false_type { }; + +template +struct __is_nt_invocable_impl<_Result, _Ret, __void_t> + : __or_, + __is_nothrow_convertible> { }; + +/// std::is_nothrow_invocable_r +template +struct is_nothrow_invocable_r + : __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>, + __call_is_nothrow_<_Fn, _ArgTypes...>>::type { }; + +/// std::is_invocable_v +template +inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; + +/// std::is_nothrow_invocable_v +template +inline constexpr bool is_nothrow_invocable_v + = is_nothrow_invocable<_Fn, _Args...>::value; + +/// std::is_invocable_r_v +template +inline constexpr bool is_invocable_r_v + = is_invocable_r<_Ret, _Fn, _Args...>::value; + +/// std::is_nothrow_invocable_r_v +template +inline constexpr bool is_nothrow_invocable_r_v + = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; +#endif // C++17 #if __cplusplus >= 201703L -#define __cpp_lib_type_trait_variable_templates 201510L - template - inline constexpr bool is_void_v = is_void<_Tp>::value; - template - inline constexpr bool is_null_pointer_v = is_null_pointer<_Tp>::value; - template - inline constexpr bool is_integral_v = is_integral<_Tp>::value; - template - inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value; - template - inline constexpr bool is_array_v = is_array<_Tp>::value; - template - inline constexpr bool is_pointer_v = is_pointer<_Tp>::value; - template - inline constexpr bool is_lvalue_reference_v = - is_lvalue_reference<_Tp>::value; - template - inline constexpr bool is_rvalue_reference_v = - is_rvalue_reference<_Tp>::value; - template - inline constexpr bool is_member_object_pointer_v = - is_member_object_pointer<_Tp>::value; - template - inline constexpr bool is_member_function_pointer_v = - is_member_function_pointer<_Tp>::value; - template - inline constexpr bool is_enum_v = is_enum<_Tp>::value; - template - inline constexpr bool is_union_v = is_union<_Tp>::value; - template - inline constexpr bool is_class_v = is_class<_Tp>::value; - template - inline constexpr bool is_function_v = is_function<_Tp>::value; - template - inline constexpr bool is_reference_v = is_reference<_Tp>::value; - template - inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value; - template - inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value; - template - inline constexpr bool is_object_v = is_object<_Tp>::value; - template - inline constexpr bool is_scalar_v = is_scalar<_Tp>::value; - template - inline constexpr bool is_compound_v = is_compound<_Tp>::value; - template - inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value; - template - inline constexpr bool is_const_v = is_const<_Tp>::value; - template - inline constexpr bool is_volatile_v = is_volatile<_Tp>::value; - template - inline constexpr bool is_trivial_v = is_trivial<_Tp>::value; - template - inline constexpr bool is_trivially_copyable_v = - is_trivially_copyable<_Tp>::value; - template - inline constexpr bool is_standard_layout_v = is_standard_layout<_Tp>::value; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - template - _GLIBCXX20_DEPRECATED("use is_standard_layout_v && is_trivial_v instead") - inline constexpr bool is_pod_v = is_pod<_Tp>::value; -#pragma GCC diagnostic pop - template - inline constexpr bool is_literal_type_v = is_literal_type<_Tp>::value; - template - inline constexpr bool is_empty_v = is_empty<_Tp>::value; - template - inline constexpr bool is_polymorphic_v = is_polymorphic<_Tp>::value; - template - inline constexpr bool is_abstract_v = is_abstract<_Tp>::value; - template - inline constexpr bool is_final_v = is_final<_Tp>::value; - template - inline constexpr bool is_signed_v = is_signed<_Tp>::value; - template - inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value; - template - inline constexpr bool is_constructible_v = - is_constructible<_Tp, _Args...>::value; - template - inline constexpr bool is_default_constructible_v = - is_default_constructible<_Tp>::value; - template - inline constexpr bool is_copy_constructible_v = - is_copy_constructible<_Tp>::value; - template - inline constexpr bool is_move_constructible_v = - is_move_constructible<_Tp>::value; - template - inline constexpr bool is_assignable_v = is_assignable<_Tp, _Up>::value; - template - inline constexpr bool is_copy_assignable_v = is_copy_assignable<_Tp>::value; - template - inline constexpr bool is_move_assignable_v = is_move_assignable<_Tp>::value; - template - inline constexpr bool is_destructible_v = is_destructible<_Tp>::value; - template - inline constexpr bool is_trivially_constructible_v = - is_trivially_constructible<_Tp, _Args...>::value; - template - inline constexpr bool is_trivially_default_constructible_v = - is_trivially_default_constructible<_Tp>::value; - template - inline constexpr bool is_trivially_copy_constructible_v = - is_trivially_copy_constructible<_Tp>::value; - template - inline constexpr bool is_trivially_move_constructible_v = - is_trivially_move_constructible<_Tp>::value; - template - inline constexpr bool is_trivially_assignable_v = - is_trivially_assignable<_Tp, _Up>::value; - template - inline constexpr bool is_trivially_copy_assignable_v = - is_trivially_copy_assignable<_Tp>::value; - template - inline constexpr bool is_trivially_move_assignable_v = - is_trivially_move_assignable<_Tp>::value; - template - inline constexpr bool is_trivially_destructible_v = - is_trivially_destructible<_Tp>::value; - template - inline constexpr bool is_nothrow_constructible_v = - is_nothrow_constructible<_Tp, _Args...>::value; - template - inline constexpr bool is_nothrow_default_constructible_v = - is_nothrow_default_constructible<_Tp>::value; - template - inline constexpr bool is_nothrow_copy_constructible_v = - is_nothrow_copy_constructible<_Tp>::value; - template - inline constexpr bool is_nothrow_move_constructible_v = - is_nothrow_move_constructible<_Tp>::value; - template - inline constexpr bool is_nothrow_assignable_v = - is_nothrow_assignable<_Tp, _Up>::value; - template - inline constexpr bool is_nothrow_copy_assignable_v = - is_nothrow_copy_assignable<_Tp>::value; - template - inline constexpr bool is_nothrow_move_assignable_v = - is_nothrow_move_assignable<_Tp>::value; - template - inline constexpr bool is_nothrow_destructible_v = - is_nothrow_destructible<_Tp>::value; - template - inline constexpr bool has_virtual_destructor_v = - has_virtual_destructor<_Tp>::value; - template - inline constexpr size_t alignment_of_v = alignment_of<_Tp>::value; - template - inline constexpr size_t rank_v = rank<_Tp>::value; - template - inline constexpr size_t extent_v = extent<_Tp, _Idx>::value; -#ifdef _GLIBCXX_BUILTIN_IS_SAME_AS - template - inline constexpr bool is_same_v = _GLIBCXX_BUILTIN_IS_SAME_AS(_Tp, _Up); -#else - template - inline constexpr bool is_same_v = std::is_same<_Tp, _Up>::value; -#endif - template - inline constexpr bool is_base_of_v = is_base_of<_Base, _Derived>::value; - template - inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value; - -#ifdef _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP -#define __cpp_lib_has_unique_object_representations 201606 - /// has_unique_object_representations - template - struct has_unique_object_representations - : bool_constant<__has_unique_object_representations( - remove_cv_t>)> { - static_assert( - std::__is_complete_or_unbounded(__type_identity<_Tp>{}), - "template argument must be a complete class or an unbounded array"); - }; - - template - inline constexpr bool has_unique_object_representations_v = - has_unique_object_representations<_Tp>::value; -#endif - -#ifdef _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE -#define __cpp_lib_is_aggregate 201703 - /// is_aggregate - template - struct is_aggregate : bool_constant<__is_aggregate(remove_cv_t<_Tp>)> {}; - - /// is_aggregate_v - template - inline constexpr bool is_aggregate_v = is_aggregate<_Tp>::value; -#endif -#endif // C++17 -} - -#endif /* _TYPE_TRAITS_ */ +# define __cpp_lib_type_trait_variable_templates 201510L +template +inline constexpr bool is_void_v = is_void<_Tp>::value; +template +inline constexpr bool is_null_pointer_v = is_null_pointer<_Tp>::value; +template +inline constexpr bool is_integral_v = is_integral<_Tp>::value; +template +inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value; +template +inline constexpr bool is_array_v = is_array<_Tp>::value; +template +inline constexpr bool is_pointer_v = is_pointer<_Tp>::value; +template +inline constexpr bool is_lvalue_reference_v = is_lvalue_reference<_Tp>::value; +template +inline constexpr bool is_rvalue_reference_v = is_rvalue_reference<_Tp>::value; +template +inline constexpr bool is_member_object_pointer_v + = is_member_object_pointer<_Tp>::value; +template +inline constexpr bool is_member_function_pointer_v + = is_member_function_pointer<_Tp>::value; +template +inline constexpr bool is_enum_v = is_enum<_Tp>::value; +template +inline constexpr bool is_union_v = is_union<_Tp>::value; +template +inline constexpr bool is_class_v = is_class<_Tp>::value; +template +inline constexpr bool is_function_v = is_function<_Tp>::value; +template +inline constexpr bool is_reference_v = is_reference<_Tp>::value; +template +inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value; +template +inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value; +template +inline constexpr bool is_object_v = is_object<_Tp>::value; +template +inline constexpr bool is_scalar_v = is_scalar<_Tp>::value; +template +inline constexpr bool is_compound_v = is_compound<_Tp>::value; +template +inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value; +template +inline constexpr bool is_const_v = is_const<_Tp>::value; +template +inline constexpr bool is_volatile_v = is_volatile<_Tp>::value; +template +inline constexpr bool is_trivial_v = is_trivial<_Tp>::value; +template +inline constexpr bool is_trivially_copyable_v + = is_trivially_copyable<_Tp>::value; +template +inline constexpr bool is_standard_layout_v = is_standard_layout<_Tp>::value; +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +template +_GLIBCXX20_DEPRECATED("use is_standard_layout_v && is_trivial_v instead") +inline constexpr bool is_pod_v = is_pod<_Tp>::value; +# pragma GCC diagnostic pop +template +inline constexpr bool is_literal_type_v = is_literal_type<_Tp>::value; +template +inline constexpr bool is_empty_v = is_empty<_Tp>::value; +template +inline constexpr bool is_polymorphic_v = is_polymorphic<_Tp>::value; +template +inline constexpr bool is_abstract_v = is_abstract<_Tp>::value; +template +inline constexpr bool is_final_v = is_final<_Tp>::value; +template +inline constexpr bool is_signed_v = is_signed<_Tp>::value; +template +inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value; +template +inline constexpr bool is_constructible_v + = is_constructible<_Tp, _Args...>::value; +template +inline constexpr bool is_default_constructible_v + = is_default_constructible<_Tp>::value; +template +inline constexpr bool is_copy_constructible_v + = is_copy_constructible<_Tp>::value; +template +inline constexpr bool is_move_constructible_v + = is_move_constructible<_Tp>::value; +template +inline constexpr bool is_assignable_v = is_assignable<_Tp, _Up>::value; +template +inline constexpr bool is_copy_assignable_v = is_copy_assignable<_Tp>::value; +template +inline constexpr bool is_move_assignable_v = is_move_assignable<_Tp>::value; +template +inline constexpr bool is_destructible_v = is_destructible<_Tp>::value; +template +inline constexpr bool is_trivially_constructible_v + = is_trivially_constructible<_Tp, _Args...>::value; +template +inline constexpr bool is_trivially_default_constructible_v + = is_trivially_default_constructible<_Tp>::value; +template +inline constexpr bool is_trivially_copy_constructible_v + = is_trivially_copy_constructible<_Tp>::value; +template +inline constexpr bool is_trivially_move_constructible_v + = is_trivially_move_constructible<_Tp>::value; +template +inline constexpr bool is_trivially_assignable_v + = is_trivially_assignable<_Tp, _Up>::value; +template +inline constexpr bool is_trivially_copy_assignable_v + = is_trivially_copy_assignable<_Tp>::value; +template +inline constexpr bool is_trivially_move_assignable_v + = is_trivially_move_assignable<_Tp>::value; +template +inline constexpr bool is_trivially_destructible_v + = is_trivially_destructible<_Tp>::value; +template +inline constexpr bool is_nothrow_constructible_v + = is_nothrow_constructible<_Tp, _Args...>::value; +template +inline constexpr bool is_nothrow_default_constructible_v + = is_nothrow_default_constructible<_Tp>::value; +template +inline constexpr bool is_nothrow_copy_constructible_v + = is_nothrow_copy_constructible<_Tp>::value; +template +inline constexpr bool is_nothrow_move_constructible_v + = is_nothrow_move_constructible<_Tp>::value; +template +inline constexpr bool is_nothrow_assignable_v + = is_nothrow_assignable<_Tp, _Up>::value; +template +inline constexpr bool is_nothrow_copy_assignable_v + = is_nothrow_copy_assignable<_Tp>::value; +template +inline constexpr bool is_nothrow_move_assignable_v + = is_nothrow_move_assignable<_Tp>::value; +template +inline constexpr bool is_nothrow_destructible_v + = is_nothrow_destructible<_Tp>::value; +template +inline constexpr bool has_virtual_destructor_v + = has_virtual_destructor<_Tp>::value; +template +inline constexpr size_t alignment_of_v = alignment_of<_Tp>::value; +template +inline constexpr size_t rank_v = rank<_Tp>::value; +template +inline constexpr size_t extent_v = extent<_Tp, _Idx>::value; +# ifdef _GLIBCXX_BUILTIN_IS_SAME_AS +template +inline constexpr bool is_same_v = _GLIBCXX_BUILTIN_IS_SAME_AS(_Tp, _Up); +# else +template +inline constexpr bool is_same_v = std::is_same<_Tp, _Up>::value; +# endif +template +inline constexpr bool is_base_of_v = is_base_of<_Base, _Derived>::value; +template +inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value; + +# ifdef _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP +# define __cpp_lib_has_unique_object_representations 201606 + +/// has_unique_object_representations +template +struct has_unique_object_representations + : bool_constant<__has_unique_object_representations( + remove_cv_t>)> { + static_assert( + std::__is_complete_or_unbounded(__type_identity<_Tp> {}), + "template argument must be a complete class or an unbounded array"); +}; + +template +inline constexpr bool has_unique_object_representations_v + = has_unique_object_representations<_Tp>::value; +# endif + +# ifdef _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE +# define __cpp_lib_is_aggregate 201703 + +/// is_aggregate +template +struct is_aggregate : bool_constant<__is_aggregate(remove_cv_t<_Tp>)> { }; + +/// is_aggregate_v +template +inline constexpr bool is_aggregate_v = is_aggregate<_Tp>::value; +# endif +#endif // C++17 +} // namespace std + +#endif /* SIMPLEKERNEL_TYPE_TRAITS */ diff --git a/src/libcxx/include/type_traits.h b/src/libcxx/include/type_traits.h index 4bce7ffac..7055ecd8c 100644 --- a/src/libcxx/include/type_traits.h +++ b/src/libcxx/include/type_traits.h @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// type_traits.h for Simple-XX/SimpleKernel. - -#ifndef _TYPE_TRAITS_H_ -#define _TYPE_TRAITS_H_ +/** + * @file type_traits.h + * @brief stl type_traits 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_TYPE_TRAITS_H +#define SIMPLEKERNEL_TYPE_TRAITS_H // 这个头文件用于提取类型信息 @@ -14,35 +25,36 @@ namespace mystl { - // helper struct +// helper struct + +template +struct m_integral_constant { + static constexpr T value = v; +}; - template - struct m_integral_constant { - static constexpr T value = v; - }; +template +using m_bool_constant = m_integral_constant; - template - using m_bool_constant = m_integral_constant; +typedef m_bool_constant m_true_type; +typedef m_bool_constant m_false_type; - typedef m_bool_constant m_true_type; - typedef m_bool_constant m_false_type; +/*****************************************************************************************/ +// type traits - /*****************************************************************************************/ - // type traits +// is_pair - // is_pair +// --- forward declaration begin +template +struct pair; - // --- forward declaration begin - template - struct pair; - // --- forward declaration end +// --- forward declaration end - template - struct is_pair : mystl::m_false_type {}; +template +struct is_pair : mystl::m_false_type { }; - template - struct is_pair> : mystl::m_true_type {}; +template +struct is_pair> : mystl::m_true_type { }; -}; +}; // namespace mystl -#endif // !_TYPE_TRAITS_H_ +#endif /* SIMPLEKERNEL_TYPE_TRAITS_H */ diff --git a/src/libcxx/include/uninitialized b/src/libcxx/include/uninitialized index 8af1f27d3..8e9af3d17 100644 --- a/src/libcxx/include/uninitialized +++ b/src/libcxx/include/uninitialized @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// uninitialized for Simple-XX/SimpleKernel. - -#ifndef _UNINITIALIZED_ -#define _UNINITIALIZED_ +/** + * @file uninitialized + * @brief stl uninitialized 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_UNINITIALIZED +#define SIMPLEKERNEL_UNINITIALIZED // 这个头文件用于对未初始化空间构造元素 @@ -17,210 +28,213 @@ namespace mystl { - /*****************************************************************************************/ - // uninitialized_copy - // 把 [first, last) 上的内容复制到以 result - // 为起始处的空间,返回复制结束的位置 - /*****************************************************************************************/ - template - ForwardIter unchecked_uninit_copy(InputIter first, InputIter last, - ForwardIter result, std::true_type) { - return mystl::copy(first, last, result); - } - - template - ForwardIter unchecked_uninit_copy(InputIter first, InputIter last, - ForwardIter result, std::false_type) { - auto cur = result; - try { - for (; first != last; ++first, ++cur) { - mystl::construct(&*cur, *first); - } - } catch (...) { - for (; result != cur; ++result) - mystl::destroy(&*result); +/*****************************************************************************************/ +// uninitialized_copy +// 把 [first, last) 上的内容复制到以 result +// 为起始处的空间,返回复制结束的位置 +/*****************************************************************************************/ +template +ForwardIter unchecked_uninit_copy(InputIter first, InputIter last, + ForwardIter result, std::true_type) { + return mystl::copy(first, last, result); +} + +template +ForwardIter unchecked_uninit_copy(InputIter first, InputIter last, + ForwardIter result, std::false_type) { + auto cur = result; + try { + for (; first != last; ++first, ++cur) { + mystl::construct(&*cur, *first); } - return cur; - } - - template - ForwardIter uninitialized_copy(InputIter first, InputIter last, - ForwardIter result) { - return mystl::unchecked_uninit_copy( - first, last, result, - std::is_trivially_copy_assignable< - typename iterator_traits::value_type>{}); - } - - /*****************************************************************************************/ - // uninitialized_copy_n - // 把 [first, first + n) 上的内容复制到以 result - // 为起始处的空间,返回复制结束的位置 - /*****************************************************************************************/ - template - ForwardIter unchecked_uninit_copy_n(InputIter first, Size n, - ForwardIter result, std::true_type) { - return mystl::copy_n(first, n, result).second; - } - - template - ForwardIter unchecked_uninit_copy_n(InputIter first, Size n, - ForwardIter result, std::false_type) { - auto cur = result; - try { - for (; n > 0; --n, ++cur, ++first) { - mystl::construct(&*cur, *first); - } - } catch (...) { - for (; result != cur; ++result) - mystl::destroy(&*result); + } catch (...) { + for (; result != cur; ++result) { + mystl::destroy(&*result); } - return cur; } - - template - ForwardIter uninitialized_copy_n(InputIter first, Size n, - ForwardIter result) { - return mystl::unchecked_uninit_copy_n( - first, n, result, - std::is_trivially_copy_assignable< - typename iterator_traits::value_type>{}); - } - - /*****************************************************************************************/ - // uninitialized_fill - // 在 [first, last) 区间内填充元素值 - /*****************************************************************************************/ - template - void unchecked_uninit_fill(ForwardIter first, ForwardIter last, - const T &value, std::true_type) { - mystl::fill(first, last, value); - } - - template - void unchecked_uninit_fill(ForwardIter first, ForwardIter last, - const T &value, std::false_type) { - auto cur = first; - try { - for (; cur != last; ++cur) { - mystl::construct(&*cur, value); - } - } catch (...) { - for (; first != cur; ++first) - mystl::destroy(&*first); + return cur; +} + +template +ForwardIter +uninitialized_copy(InputIter first, InputIter last, ForwardIter result) { + return mystl::unchecked_uninit_copy( + first, last, result, + std::is_trivially_copy_assignable< + typename iterator_traits::value_type> {}); +} + +/*****************************************************************************************/ +// uninitialized_copy_n +// 把 [first, first + n) 上的内容复制到以 result +// 为起始处的空间,返回复制结束的位置 +/*****************************************************************************************/ +template +ForwardIter unchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, + std::true_type) { + return mystl::copy_n(first, n, result).second; +} + +template +ForwardIter unchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, + std::false_type) { + auto cur = result; + try { + for (; n > 0; --n, ++cur, ++first) { + mystl::construct(&*cur, *first); } - } - - template - void uninitialized_fill(ForwardIter first, ForwardIter last, - const T &value) { - mystl::unchecked_uninit_fill( - first, last, value, - std::is_trivially_copy_assignable< - typename iterator_traits::value_type>{}); - } - - /*****************************************************************************************/ - // uninitialized_fill_n - // 从 first 位置开始,填充 n 个元素值,返回填充结束的位置 - /*****************************************************************************************/ - template - ForwardIter unchecked_uninit_fill_n(ForwardIter first, Size n, - const T &value, std::true_type) { - return mystl::fill_n(first, n, value); - } - - template - ForwardIter unchecked_uninit_fill_n(ForwardIter first, Size n, - const T &value, std::false_type) { - auto cur = first; - try { - for (; n > 0; --n, ++cur) { - mystl::construct(&*cur, value); - } - } catch (...) { - for (; first != cur; ++first) - mystl::destroy(&*first); + } catch (...) { + for (; result != cur; ++result) { + mystl::destroy(&*result); } - return cur; } - - template - ForwardIter uninitialized_fill_n(ForwardIter first, Size n, - const T &value) { - return mystl::unchecked_uninit_fill_n( - first, n, value, - std::is_trivially_copy_assignable< - typename iterator_traits::value_type>{}); - } - - /*****************************************************************************************/ - // uninitialized_move - // 把[first, last)上的内容移动到以 result 为起始处的空间,返回移动结束的位置 - /*****************************************************************************************/ - template - ForwardIter unchecked_uninit_move(InputIter first, InputIter last, - ForwardIter result, std::true_type) { - return mystl::move(first, last, result); - } - - template - ForwardIter unchecked_uninit_move(InputIter first, InputIter last, - ForwardIter result, std::false_type) { - ForwardIter cur = result; - try { - for (; first != last; ++first, ++cur) { - mystl::construct(&*cur, mystl::move(*first)); - } - } catch (...) { mystl::destroy(result, cur); } - return cur; - } - - template - ForwardIter uninitialized_move(InputIter first, InputIter last, - ForwardIter result) { - return mystl::unchecked_uninit_move( - first, last, result, - std::is_trivially_move_assignable< - typename iterator_traits::value_type>{}); + return cur; +} + +template +ForwardIter uninitialized_copy_n(InputIter first, Size n, ForwardIter result) { + return mystl::unchecked_uninit_copy_n( + first, n, result, + std::is_trivially_copy_assignable< + typename iterator_traits::value_type> {}); +} + +/*****************************************************************************************/ +// uninitialized_fill +// 在 [first, last) 区间内填充元素值 +/*****************************************************************************************/ +template +void unchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, + std::true_type) { + mystl::fill(first, last, value); +} + +template +void unchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, + std::false_type) { + auto cur = first; + try { + for (; cur != last; ++cur) { + mystl::construct(&*cur, value); + } + } catch (...) { + for (; first != cur; ++first) { + mystl::destroy(&*first); + } } - - /*****************************************************************************************/ - // uninitialized_move_n - // 把[first, first + n)上的内容移动到以 result - // 为起始处的空间,返回移动结束的位置 - /*****************************************************************************************/ - template - ForwardIter unchecked_uninit_move_n(InputIter first, Size n, - ForwardIter result, std::true_type) { - return mystl::move(first, first + n, result); +} + +template +void uninitialized_fill(ForwardIter first, ForwardIter last, const T& value) { + mystl::unchecked_uninit_fill( + first, last, value, + std::is_trivially_copy_assignable< + typename iterator_traits::value_type> {}); +} + +/*****************************************************************************************/ +// uninitialized_fill_n +// 从 first 位置开始,填充 n 个元素值,返回填充结束的位置 +/*****************************************************************************************/ +template +ForwardIter unchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, + std::true_type) { + return mystl::fill_n(first, n, value); +} + +template +ForwardIter unchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, + std::false_type) { + auto cur = first; + try { + for (; n > 0; --n, ++cur) { + mystl::construct(&*cur, value); + } + } catch (...) { + for (; first != cur; ++first) { + mystl::destroy(&*first); + } } - - template - ForwardIter unchecked_uninit_move_n(InputIter first, Size n, - ForwardIter result, std::false_type) { - auto cur = result; - try { - for (; n > 0; --n, ++first, ++cur) { - mystl::construct(&*cur, mystl::move(*first)); - } - } catch (...) { - for (; result != cur; ++result) - mystl::destroy(&*result); - throw; + return cur; +} + +template +ForwardIter uninitialized_fill_n(ForwardIter first, Size n, const T& value) { + return mystl::unchecked_uninit_fill_n( + first, n, value, + std::is_trivially_copy_assignable< + typename iterator_traits::value_type> {}); +} + +/*****************************************************************************************/ +// uninitialized_move +// 把[first, last)上的内容移动到以 result 为起始处的空间,返回移动结束的位置 +/*****************************************************************************************/ +template +ForwardIter unchecked_uninit_move(InputIter first, InputIter last, + ForwardIter result, std::true_type) { + return mystl::move(first, last, result); +} + +template +ForwardIter unchecked_uninit_move(InputIter first, InputIter last, + ForwardIter result, std::false_type) { + ForwardIter cur = result; + try { + for (; first != last; ++first, ++cur) { + mystl::construct(&*cur, mystl::move(*first)); + } + } catch (...) { + mystl::destroy(result, cur); + } + return cur; +} + +template +ForwardIter +uninitialized_move(InputIter first, InputIter last, ForwardIter result) { + return mystl::unchecked_uninit_move( + first, last, result, + std::is_trivially_move_assignable< + typename iterator_traits::value_type> {}); +} + +/*****************************************************************************************/ +// uninitialized_move_n +// 把[first, first + n)上的内容移动到以 result +// 为起始处的空间,返回移动结束的位置 +/*****************************************************************************************/ +template +ForwardIter unchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, + std::true_type) { + return mystl::move(first, first + n, result); +} + +template +ForwardIter unchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, + std::false_type) { + auto cur = result; + try { + for (; n > 0; --n, ++first, ++cur) { + mystl::construct(&*cur, mystl::move(*first)); } - return cur; + } catch (...) { + for (; result != cur; ++result) { + mystl::destroy(&*result); + } + throw; } + return cur; +} - template - ForwardIter uninitialized_move_n(InputIter first, Size n, - ForwardIter result) { - return mystl::unchecked_uninit_move_n( - first, n, result, - std::is_trivially_move_assignable< - typename iterator_traits::value_type>{}); - } +template +ForwardIter uninitialized_move_n(InputIter first, Size n, ForwardIter result) { + return mystl::unchecked_uninit_move_n( + first, n, result, + std::is_trivially_move_assignable< + typename iterator_traits::value_type> {}); +} -}; +}; // namespace mystl -#endif /* _UNINITIALIZED_ */ +#endif /* SIMPLEKERNEL_UNINITIALIZED */ diff --git a/src/libcxx/include/unordered_map b/src/libcxx/include/unordered_map index 3f9164650..06a4f9b81 100644 --- a/src/libcxx/include/unordered_map +++ b/src/libcxx/include/unordered_map @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// unordered_map for Simple-XX/SimpleKernel. - -#ifndef _UNORDERED_MAP_ -#define _UNORDERED_MAP_ +/** + * @file unordered_map + * @brief stl unordered_map 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_UNORDERED_MAP +#define SIMPLEKERNEL_UNORDERED_MAP // 这个头文件包含两个模板类 unordered_map 和 unordered_multimap // 功能与用法与 map 和 multimap 类似,不同的是使用 hashtable @@ -24,645 +35,689 @@ namespace mystl { - // 模板类 unordered_map,键值不允许重复 - // 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 - // mystl::hash 参数四代表键值比较方式,缺省使用 mystl::equal_to - template , - class KeyEqual = mystl::equal_to> - class unordered_map { - private: - // 使用 hashtable 作为底层机制 - typedef hashtable, Hash, KeyEqual> base_type; - base_type ht_; - - public: - // 使用 hashtable 的型别 - - typedef typename base_type::allocator_type allocator_type; - typedef typename base_type::key_type key_type; - typedef typename base_type::mapped_type mapped_type; - typedef typename base_type::value_type value_type; - typedef typename base_type::hasher hasher; - typedef typename base_type::key_equal key_equal; - - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; - - typedef typename base_type::iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::local_iterator local_iterator; - typedef typename base_type::const_local_iterator const_local_iterator; - - allocator_type get_allocator() const { - return ht_.get_allocator(); - } +// 模板类 unordered_map,键值不允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 +// mystl::hash 参数四代表键值比较方式,缺省使用 mystl::equal_to +template , + class KeyEqual = mystl::equal_to> +class unordered_map { +private: + // 使用 hashtable 作为底层机制 + typedef hashtable, Hash, KeyEqual> base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::mapped_type mapped_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { + return ht_.get_allocator(); + } - public: - // 构造、复制、移动、析构函数 +public: + // 构造、复制、移动、析构函数 - unordered_map() : ht_(100, Hash(), KeyEqual()) { - } + unordered_map() : ht_(100, Hash(), KeyEqual()) { + } - explicit unordered_map(size_type bucket_count, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(bucket_count, hash, equal) { - } + explicit unordered_map(size_type bucket_count, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(bucket_count, hash, equal) { + } - template - unordered_map(InputIterator first, InputIterator last, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(mystl::max(bucket_count, static_cast( - mystl::distance(first, last))), - hash, equal) { - for (; first != last; ++first) - ht_.insert_unique_noresize(*first); + template + unordered_map(InputIterator first, InputIterator last, + const size_type bucket_count = 100, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, + static_cast(mystl::distance(first, last))), + hash, equal) { + for (; first != last; ++first) { + ht_.insert_unique_noresize(*first); } + } - unordered_map(std::initializer_list ilist, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual & equal = KeyEqual()) - : ht_(mystl::max(bucket_count, - static_cast(ilist.size())), - hash, equal) { - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_unique_noresize(*first); + unordered_map(std::initializer_list ilist, + const size_type bucket_count = 100, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, static_cast(ilist.size())), + hash, equal) { + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_unique_noresize(*first); } + } - unordered_map(const unordered_map &rhs) : ht_(rhs.ht_) { - } - unordered_map(unordered_map &&rhs) noexcept - : ht_(mystl::move(rhs.ht_)) { - } + unordered_map(const unordered_map& rhs) : ht_(rhs.ht_) { + } - unordered_map &operator=(const unordered_map &rhs) { - ht_ = rhs.ht_; - return *this; - } - unordered_map &operator=(unordered_map &&rhs) { - ht_ = mystl::move(rhs.ht_); - return *this; - } + unordered_map(unordered_map&& rhs) noexcept : ht_(mystl::move(rhs.ht_)) { + } + + unordered_map& operator=(const unordered_map& rhs) { + ht_ = rhs.ht_; + return *this; + } - unordered_map &operator=(std::initializer_list ilist) { - ht_.clear(); - ht_.reserve(ilist.size()); - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_unique_noresize(*first); - return *this; + unordered_map& operator=(unordered_map&& rhs) { + ht_ = mystl::move(rhs.ht_); + return *this; + } + + unordered_map& operator=(std::initializer_list ilist) { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_unique_noresize(*first); } + return *this; + } - ~unordered_map() = default; + ~unordered_map() = default; - // 迭代器相关 + // 迭代器相关 - iterator begin() noexcept { - return ht_.begin(); - } - const_iterator begin() const noexcept { - return ht_.begin(); - } - iterator end() noexcept { - return ht_.end(); - } - const_iterator end() const noexcept { - return ht_.end(); - } + iterator begin() noexcept { + return ht_.begin(); + } - const_iterator cbegin() const noexcept { - return ht_.cbegin(); - } - const_iterator cend() const noexcept { - return ht_.cend(); - } + const_iterator begin() const noexcept { + return ht_.begin(); + } - // 容量相关 + iterator end() noexcept { + return ht_.end(); + } - bool empty() const noexcept { - return ht_.empty(); - } - size_type size() const noexcept { - return ht_.size(); - } - size_type max_size() const noexcept { - return ht_.max_size(); - } + const_iterator end() const noexcept { + return ht_.end(); + } - // 修改容器操作 + const_iterator cbegin() const noexcept { + return ht_.cbegin(); + } - // empalce / empalce_hint + const_iterator cend() const noexcept { + return ht_.cend(); + } - template - pair emplace(Args &&...args) { - return ht_.emplace_unique(mystl::forward(args)...); - } + // 容量相关 - template - iterator emplace_hint(const_iterator hint, Args &&...args) { - return ht_.emplace_unique_use_hint(hint, - mystl::forward(args)...); - } + bool empty() const noexcept { + return ht_.empty(); + } - // insert + size_type size() const noexcept { + return ht_.size(); + } - pair insert(const value_type &value) { - return ht_.insert_unique(value); - } - pair insert(value_type &&value) { - return ht_.emplace_unique(mystl::move(value)); - } + size_type max_size() const noexcept { + return ht_.max_size(); + } - iterator insert(const_iterator hint, const value_type &value) { - return ht_.insert_unique_use_hint(hint, value); - } - iterator insert(const_iterator hint, value_type &&value) { - return ht_.emplace_unique_use_hint(hint, mystl::move(value)); - } + // 修改容器操作 - template - void insert(InputIterator first, InputIterator last) { - ht_.insert_unique(first, last); - } + // empalce / empalce_hint - // erase / clear + template + pair emplace(Args&&... args) { + return ht_.emplace_unique(mystl::forward(args)...); + } - void erase(iterator it) { - ht_.erase(it); - } - void erase(iterator first, iterator last) { - ht_.erase(first, last); - } + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return ht_.emplace_unique_use_hint(hint, mystl::forward(args)...); + } - size_type erase(const key_type &key) { - return ht_.erase_unique(key); - } + // insert - void clear() { - ht_.clear(); - } + pair insert(const value_type& value) { + return ht_.insert_unique(value); + } - void swap(unordered_map &other) noexcept { - ht_.swap(other.ht_); - } + pair insert(value_type&& value) { + return ht_.emplace_unique(mystl::move(value)); + } - // 查找相关 + iterator insert(const_iterator hint, const value_type& value) { + return ht_.insert_unique_use_hint(hint, value); + } - mapped_type &at(const key_type &key) { - iterator it = ht_.find(key); - THROW_OUT_OF_RANGE_IF( - it.node == nullptr, - "unordered_map no such element exists"); - return it->second; - } - const mapped_type &at(const key_type &key) const { - iterator it = ht_.find(key); - THROW_OUT_OF_RANGE_IF( - it.node == nullptr, - "unordered_map no such element exists"); - return it->second; - } + iterator insert(const_iterator hint, value_type&& value) { + return ht_.emplace_unique_use_hint(hint, mystl::move(value)); + } - mapped_type &operator[](const key_type &key) { - iterator it = ht_.find(key); - if (it.node == nullptr) - it = ht_.emplace_unique(key, T{}).first; - return it->second; - } - mapped_type &operator[](key_type &&key) { - iterator it = ht_.find(key); - if (it.node == nullptr) - it = ht_.emplace_unique(mystl::move(key), T{}).first; - return it->second; - } + template + void insert(InputIterator first, InputIterator last) { + ht_.insert_unique(first, last); + } - size_type count(const key_type &key) const { - return ht_.count(key); - } + // erase / clear - iterator find(const key_type &key) { - return ht_.find(key); - } - const_iterator find(const key_type &key) const { - return ht_.find(key); - } + void erase(iterator it) { + ht_.erase(it); + } - pair equal_range(const key_type &key) { - return ht_.equal_range_unique(key); - } - pair - equal_range(const key_type &key) const { - return ht_.equal_range_unique(key); - } + void erase(iterator first, iterator last) { + ht_.erase(first, last); + } - // bucket interface + size_type erase(const key_type& key) { + return ht_.erase_unique(key); + } - local_iterator begin(size_type n) noexcept { - return ht_.begin(n); - } - const_local_iterator begin(size_type n) const noexcept { - return ht_.begin(n); - } - const_local_iterator cbegin(size_type n) const noexcept { - return ht_.cbegin(n); - } + void clear() { + ht_.clear(); + } - local_iterator end(size_type n) noexcept { - return ht_.end(n); - } - const_local_iterator end(size_type n) const noexcept { - return ht_.end(n); - } - const_local_iterator cend(size_type n) const noexcept { - return ht_.cend(n); - } + void swap(unordered_map& other) noexcept { + ht_.swap(other.ht_); + } - size_type bucket_count() const noexcept { - return ht_.bucket_count(); - } - size_type max_bucket_count() const noexcept { - return ht_.max_bucket_count(); - } + // 查找相关 - size_type bucket_size(size_type n) const noexcept { - return ht_.bucket_size(n); - } - size_type bucket(const key_type &key) const { - return ht_.bucket(key); - } + mapped_type& at(const key_type& key) { + iterator it = ht_.find(key); + THROW_OUT_OF_RANGE_IF(it.node == nullptr, + "unordered_map no such element exists"); + return it->second; + } - // hash policy + const mapped_type& at(const key_type& key) const { + iterator it = ht_.find(key); + THROW_OUT_OF_RANGE_IF(it.node == nullptr, + "unordered_map no such element exists"); + return it->second; + } - float load_factor() const noexcept { - return ht_.load_factor(); + mapped_type& operator[](const key_type& key) { + iterator it = ht_.find(key); + if (it.node == nullptr) { + it = ht_.emplace_unique(key, T {}).first; } + return it->second; + } - float max_load_factor() const noexcept { - return ht_.max_load_factor(); - } - void max_load_factor(float ml) { - ht_.max_load_factor(ml); + mapped_type& operator[](key_type&& key) { + iterator it = ht_.find(key); + if (it.node == nullptr) { + it = ht_.emplace_unique(mystl::move(key), T {}).first; } + return it->second; + } - void rehash(size_type count) { - ht_.rehash(count); - } - void reserve(size_type count) { - ht_.reserve(count); - } + size_type count(const key_type& key) const { + return ht_.count(key); + } - hasher hash_fcn() const { - return ht_.hash_fcn(); - } - key_equal key_eq() const { - return ht_.key_eq(); - } + iterator find(const key_type& key) { + return ht_.find(key); + } - public: - friend bool operator==(const unordered_map &lhs, - const unordered_map &rhs) { - return lhs.ht_.equal_range_unique(rhs.ht_); - } - friend bool operator!=(const unordered_map &lhs, - const unordered_map &rhs) { - return !lhs.ht_.equal_range_unique(rhs.ht_); - } - }; - - // 重载比较操作符 - template - bool operator==(const unordered_map &lhs, - const unordered_map &rhs) { - return lhs == rhs; - } - - template - bool operator!=(const unordered_map &lhs, - const unordered_map &rhs) { - return lhs != rhs; - } - - // 重载 mystl 的 swap - template - void swap(unordered_map &lhs, - unordered_map &rhs) { - lhs.swap(rhs); - } - - /*****************************************************************************************/ - - // 模板类 unordered_multimap,键值允许重复 - // 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 - // mystl::hash 参数四代表键值比较方式,缺省使用 mystl::equal_to - template , - class KeyEqual = mystl::equal_to> - class unordered_multimap { - private: - // 使用 hashtable 作为底层机制 - typedef hashtable, Hash, KeyEqual> base_type; - base_type ht_; - - public: - // 使用 hashtable 的型别 - typedef typename base_type::allocator_type allocator_type; - typedef typename base_type::key_type key_type; - typedef typename base_type::mapped_type mapped_type; - typedef typename base_type::value_type value_type; - typedef typename base_type::hasher hasher; - typedef typename base_type::key_equal key_equal; - - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; - - typedef typename base_type::iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::local_iterator local_iterator; - typedef typename base_type::const_local_iterator const_local_iterator; - - allocator_type get_allocator() const { - return ht_.get_allocator(); - } + const_iterator find(const key_type& key) const { + return ht_.find(key); + } - public: - // 构造、复制、移动函数 + pair equal_range(const key_type& key) { + return ht_.equal_range_unique(key); + } - unordered_multimap() : ht_(100, Hash(), KeyEqual()) { - } + pair + equal_range(const key_type& key) const { + return ht_.equal_range_unique(key); + } - explicit unordered_multimap(size_type bucket_count, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(bucket_count, hash, equal) { - } + // bucket interface - template - unordered_multimap(InputIterator first, InputIterator last, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(mystl::max(bucket_count, static_cast( - mystl::distance(first, last))), - hash, equal) { - for (; first != last; ++first) - ht_.insert_multi_noresize(*first); - } + local_iterator begin(size_type n) noexcept { + return ht_.begin(n); + } - unordered_multimap(std::initializer_list ilist, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual & equal = KeyEqual()) - : ht_(mystl::max(bucket_count, - static_cast(ilist.size())), - hash, equal) { - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_multi_noresize(*first); - } + const_local_iterator begin(size_type n) const noexcept { + return ht_.begin(n); + } - unordered_multimap(const unordered_multimap &rhs) : ht_(rhs.ht_) { - } - unordered_multimap(unordered_multimap &&rhs) noexcept - : ht_(mystl::move(rhs.ht_)) { - } + const_local_iterator cbegin(size_type n) const noexcept { + return ht_.cbegin(n); + } - unordered_multimap &operator=(const unordered_multimap &rhs) { - ht_ = rhs.ht_; - return *this; - } - unordered_multimap &operator=(unordered_multimap &&rhs) { - ht_ = mystl::move(rhs.ht_); - return *this; - } + local_iterator end(size_type n) noexcept { + return ht_.end(n); + } - unordered_multimap &operator=(std::initializer_list ilist) { - ht_.clear(); - ht_.reserve(ilist.size()); - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_multi_noresize(*first); - return *this; - } + const_local_iterator end(size_type n) const noexcept { + return ht_.end(n); + } - ~unordered_multimap() = default; + const_local_iterator cend(size_type n) const noexcept { + return ht_.cend(n); + } - // 迭代器相关 + size_type bucket_count() const noexcept { + return ht_.bucket_count(); + } - iterator begin() noexcept { - return ht_.begin(); - } - const_iterator begin() const noexcept { - return ht_.begin(); - } - iterator end() noexcept { - return ht_.end(); - } - const_iterator end() const noexcept { - return ht_.end(); - } + size_type max_bucket_count() const noexcept { + return ht_.max_bucket_count(); + } - const_iterator cbegin() const noexcept { - return ht_.cbegin(); - } - const_iterator cend() const noexcept { - return ht_.cend(); - } + size_type bucket_size(size_type n) const noexcept { + return ht_.bucket_size(n); + } - // 容量相关 + size_type bucket(const key_type& key) const { + return ht_.bucket(key); + } - bool empty() const noexcept { - return ht_.empty(); - } - size_type size() const noexcept { - return ht_.size(); - } - size_type max_size() const noexcept { - return ht_.max_size(); - } + // hash policy - // 修改容器相关 + float load_factor() const noexcept { + return ht_.load_factor(); + } - // emplace / emplace_hint + float max_load_factor() const noexcept { + return ht_.max_load_factor(); + } - template - iterator emplace(Args &&...args) { - return ht_.emplace_multi(mystl::forward(args)...); - } + void max_load_factor(float ml) { + ht_.max_load_factor(ml); + } - template - iterator emplace_hint(const_iterator hint, Args &&...args) { - return ht_.emplace_multi_use_hint(hint, - mystl::forward(args)...); - } + void rehash(size_type count) { + ht_.rehash(count); + } - // insert + void reserve(size_type count) { + ht_.reserve(count); + } - iterator insert(const value_type &value) { - return ht_.insert_multi(value); - } - iterator insert(value_type &&value) { - return ht_.emplace_multi(mystl::move(value)); - } + hasher hash_fcn() const { + return ht_.hash_fcn(); + } - iterator insert(const_iterator hint, const value_type &value) { - return ht_.insert_multi_use_hint(hint, value); - } - iterator insert(const_iterator hint, value_type &&value) { - return ht_.emplace_multi_use_hint(hint, mystl::move(value)); - } + key_equal key_eq() const { + return ht_.key_eq(); + } - template - void insert(InputIterator first, InputIterator last) { - ht_.insert_multi(first, last); - } +public: + friend bool operator==(const unordered_map& lhs, const unordered_map& rhs) { + return lhs.ht_.equal_range_unique(rhs.ht_); + } - // erase / clear + friend bool operator!=(const unordered_map& lhs, const unordered_map& rhs) { + return !lhs.ht_.equal_range_unique(rhs.ht_); + } +}; - void erase(iterator it) { - ht_.erase(it); - } - void erase(iterator first, iterator last) { - ht_.erase(first, last); - } +// 重载比较操作符 +template +bool operator==(const unordered_map& lhs, + const unordered_map& rhs) { + return lhs == rhs; +} + +template +bool operator!=(const unordered_map& lhs, + const unordered_map& rhs) { + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_map& lhs, + unordered_map& rhs) { + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 unordered_multimap,键值允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 +// mystl::hash 参数四代表键值比较方式,缺省使用 mystl::equal_to +template , + class KeyEqual = mystl::equal_to> +class unordered_multimap { +private: + // 使用 hashtable 作为底层机制 + typedef hashtable, Hash, KeyEqual> base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::mapped_type mapped_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { + return ht_.get_allocator(); + } - size_type erase(const key_type &key) { - return ht_.erase_multi(key); - } +public: + // 构造、复制、移动函数 + + unordered_multimap() : ht_(100, Hash(), KeyEqual()) { + } - void clear() { - ht_.clear(); + explicit unordered_multimap(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(bucket_count, hash, equal) { + } + + template + unordered_multimap(InputIterator first, InputIterator last, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, + static_cast(mystl::distance(first, last))), + hash, equal) { + for (; first != last; ++first) { + ht_.insert_multi_noresize(*first); } + } - void swap(unordered_multimap &other) noexcept { - ht_.swap(other.ht_); + unordered_multimap(std::initializer_list ilist, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, static_cast(ilist.size())), + hash, equal) { + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_multi_noresize(*first); } + } - // 查找相关 + unordered_multimap(const unordered_multimap& rhs) : ht_(rhs.ht_) { + } - size_type count(const key_type &key) const { - return ht_.count(key); - } + unordered_multimap(unordered_multimap&& rhs) noexcept + : ht_(mystl::move(rhs.ht_)) { + } - iterator find(const key_type &key) { - return ht_.find(key); - } - const_iterator find(const key_type &key) const { - return ht_.find(key); - } + unordered_multimap& operator=(const unordered_multimap& rhs) { + ht_ = rhs.ht_; + return *this; + } - pair equal_range(const key_type &key) { - return ht_.equal_range_multi(key); - } - pair - equal_range(const key_type &key) const { - return ht_.equal_range_multi(key); + unordered_multimap& operator=(unordered_multimap&& rhs) { + ht_ = mystl::move(rhs.ht_); + return *this; + } + + unordered_multimap& operator=(std::initializer_list ilist) { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_multi_noresize(*first); } + return *this; + } - // bucket interface + ~unordered_multimap() = default; - local_iterator begin(size_type n) noexcept { - return ht_.begin(n); - } - const_local_iterator begin(size_type n) const noexcept { - return ht_.begin(n); - } - const_local_iterator cbegin(size_type n) const noexcept { - return ht_.cbegin(n); - } + // 迭代器相关 - local_iterator end(size_type n) noexcept { - return ht_.end(n); - } - const_local_iterator end(size_type n) const noexcept { - return ht_.end(n); - } - const_local_iterator cend(size_type n) const noexcept { - return ht_.cend(n); - } + iterator begin() noexcept { + return ht_.begin(); + } - size_type bucket_count() const noexcept { - return ht_.bucket_count(); - } - size_type max_bucket_count() const noexcept { - return ht_.max_bucket_count(); - } + const_iterator begin() const noexcept { + return ht_.begin(); + } - size_type bucket_size(size_type n) const noexcept { - return ht_.bucket_size(n); - } - size_type bucket(const key_type &key) const { - return ht_.bucket(key); - } + iterator end() noexcept { + return ht_.end(); + } - // hash policy + const_iterator end() const noexcept { + return ht_.end(); + } - float load_factor() const noexcept { - return ht_.load_factor(); - } + const_iterator cbegin() const noexcept { + return ht_.cbegin(); + } - float max_load_factor() const noexcept { - return ht_.max_load_factor(); - } - void max_load_factor(float ml) { - ht_.max_load_factor(ml); - } + const_iterator cend() const noexcept { + return ht_.cend(); + } - void rehash(size_type count) { - ht_.rehash(count); - } - void reserve(size_type count) { - ht_.reserve(count); - } + // 容量相关 - hasher hash_fcn() const { - return ht_.hash_fcn(); - } - key_equal key_eq() const { - return ht_.key_eq(); - } + bool empty() const noexcept { + return ht_.empty(); + } - public: - friend bool operator==(const unordered_multimap &lhs, - const unordered_multimap &rhs) { - return lhs.ht_.equal_range_multi(rhs.ht_); - } - friend bool operator!=(const unordered_multimap &lhs, - const unordered_multimap &rhs) { - return !lhs.ht_.equal_range_multi(rhs.ht_); - } - }; + size_type size() const noexcept { + return ht_.size(); + } + + size_type max_size() const noexcept { + return ht_.max_size(); + } + + // 修改容器相关 + + // emplace / emplace_hint + + template + iterator emplace(Args&&... args) { + return ht_.emplace_multi(mystl::forward(args)...); + } + + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return ht_.emplace_multi_use_hint(hint, mystl::forward(args)...); + } - // 重载比较操作符 - template - bool operator==(const unordered_multimap &lhs, - const unordered_multimap &rhs) { - return lhs == rhs; + // insert + + iterator insert(const value_type& value) { + return ht_.insert_multi(value); + } + + iterator insert(value_type&& value) { + return ht_.emplace_multi(mystl::move(value)); + } + + iterator insert(const_iterator hint, const value_type& value) { + return ht_.insert_multi_use_hint(hint, value); + } + + iterator insert(const_iterator hint, value_type&& value) { + return ht_.emplace_multi_use_hint(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) { + ht_.insert_multi(first, last); + } + + // erase / clear + + void erase(iterator it) { + ht_.erase(it); + } + + void erase(iterator first, iterator last) { + ht_.erase(first, last); + } + + size_type erase(const key_type& key) { + return ht_.erase_multi(key); + } + + void clear() { + ht_.clear(); + } + + void swap(unordered_multimap& other) noexcept { + ht_.swap(other.ht_); + } + + // 查找相关 + + size_type count(const key_type& key) const { + return ht_.count(key); + } + + iterator find(const key_type& key) { + return ht_.find(key); + } + + const_iterator find(const key_type& key) const { + return ht_.find(key); + } + + pair equal_range(const key_type& key) { + return ht_.equal_range_multi(key); + } + + pair + equal_range(const key_type& key) const { + return ht_.equal_range_multi(key); + } + + // bucket interface + + local_iterator begin(size_type n) noexcept { + return ht_.begin(n); + } + + const_local_iterator begin(size_type n) const noexcept { + return ht_.begin(n); + } + + const_local_iterator cbegin(size_type n) const noexcept { + return ht_.cbegin(n); + } + + local_iterator end(size_type n) noexcept { + return ht_.end(n); + } + + const_local_iterator end(size_type n) const noexcept { + return ht_.end(n); } - template - bool operator!=(const unordered_multimap &lhs, - const unordered_multimap &rhs) { - return lhs != rhs; + const_local_iterator cend(size_type n) const noexcept { + return ht_.cend(n); } - // 重载 mystl 的 swap - template - void swap(unordered_multimap &lhs, - unordered_multimap &rhs) { - lhs.swap(rhs); + size_type bucket_count() const noexcept { + return ht_.bucket_count(); } + size_type max_bucket_count() const noexcept { + return ht_.max_bucket_count(); + } + + size_type bucket_size(size_type n) const noexcept { + return ht_.bucket_size(n); + } + + size_type bucket(const key_type& key) const { + return ht_.bucket(key); + } + + // hash policy + + float load_factor() const noexcept { + return ht_.load_factor(); + } + + float max_load_factor() const noexcept { + return ht_.max_load_factor(); + } + + void max_load_factor(float ml) { + ht_.max_load_factor(ml); + } + + void rehash(size_type count) { + ht_.rehash(count); + } + + void reserve(size_type count) { + ht_.reserve(count); + } + + hasher hash_fcn() const { + return ht_.hash_fcn(); + } + + key_equal key_eq() const { + return ht_.key_eq(); + } + +public: + friend bool + operator==(const unordered_multimap& lhs, const unordered_multimap& rhs) { + return lhs.ht_.equal_range_multi(rhs.ht_); + } + + friend bool + operator!=(const unordered_multimap& lhs, const unordered_multimap& rhs) { + return !lhs.ht_.equal_range_multi(rhs.ht_); + } }; -#endif /* _UNORDERED_MAP_ */ +// 重载比较操作符 +template +bool operator==(const unordered_multimap& lhs, + const unordered_multimap& rhs) { + return lhs == rhs; +} + +template +bool operator!=(const unordered_multimap& lhs, + const unordered_multimap& rhs) { + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_multimap& lhs, + unordered_multimap& rhs) { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_UNORDERED_MAP */ diff --git a/src/libcxx/include/unordered_set b/src/libcxx/include/unordered_set index c6cd19025..04b8dd750 100644 --- a/src/libcxx/include/unordered_set +++ b/src/libcxx/include/unordered_set @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// unordered_set for Simple-XX/SimpleKernel. - -#ifndef _UNORDERED_SET_ -#define _UNORDERED_SET_ +/** + * @file unordered_set + * @brief stl unordered_set 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_UNORDERED_SET +#define SIMPLEKERNEL_UNORDERED_SET // 这个头文件包含两个模板类 unordered_set 和 unordered_multiset // 功能与用法与 set 和 multiset 类似,不同的是使用 hashtable @@ -24,614 +35,656 @@ namespace mystl { - // 模板类 unordered_set,键值不允许重复 - // 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash, - // 参数三代表键值比较方式,缺省使用 mystl::equal_to - template , - class KeyEqual = mystl::equal_to> - class unordered_set { - private: - // 使用 hashtable 作为底层机制 - typedef hashtable base_type; - base_type ht_; - - public: - // 使用 hashtable 的型别 - typedef typename base_type::allocator_type allocator_type; - typedef typename base_type::key_type key_type; - typedef typename base_type::value_type value_type; - typedef typename base_type::hasher hasher; - typedef typename base_type::key_equal key_equal; - - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; - - typedef typename base_type::const_iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::const_local_iterator local_iterator; - typedef typename base_type::const_local_iterator const_local_iterator; - - allocator_type get_allocator() const { - return ht_.get_allocator(); - } +// 模板类 unordered_set,键值不允许重复 +// 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash, +// 参数三代表键值比较方式,缺省使用 mystl::equal_to +template , + class KeyEqual = mystl::equal_to> +class unordered_set { +private: + // 使用 hashtable 作为底层机制 + typedef hashtable base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { + return ht_.get_allocator(); + } - public: - // 构造、复制、移动函数 +public: + // 构造、复制、移动函数 - unordered_set() : ht_(100, Hash(), KeyEqual()) { - } + unordered_set() : ht_(100, Hash(), KeyEqual()) { + } - explicit unordered_set(size_type bucket_count, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(bucket_count, hash, equal) { - } + explicit unordered_set(size_type bucket_count, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(bucket_count, hash, equal) { + } - template - unordered_set(InputIterator first, InputIterator last, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(mystl::max(bucket_count, static_cast( - mystl::distance(first, last))), - hash, equal) { - for (; first != last; ++first) - ht_.insert_unique_noresize(*first); + template + unordered_set(InputIterator first, InputIterator last, + const size_type bucket_count = 100, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, + static_cast(mystl::distance(first, last))), + hash, equal) { + for (; first != last; ++first) { + ht_.insert_unique_noresize(*first); } + } - unordered_set(std::initializer_list ilist, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual & equal = KeyEqual()) - : ht_(mystl::max(bucket_count, - static_cast(ilist.size())), - hash, equal) { - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_unique_noresize(*first); + unordered_set(std::initializer_list ilist, + const size_type bucket_count = 100, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, static_cast(ilist.size())), + hash, equal) { + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_unique_noresize(*first); } + } - unordered_set(const unordered_set &rhs) : ht_(rhs.ht_) { - } - unordered_set(unordered_set &&rhs) noexcept - : ht_(mystl::move(rhs.ht_)) { - } + unordered_set(const unordered_set& rhs) : ht_(rhs.ht_) { + } - unordered_set &operator=(const unordered_set &rhs) { - ht_ = rhs.ht_; - return *this; - } - unordered_set &operator=(unordered_set &&rhs) { - ht_ = mystl::move(rhs.ht_); - return *this; - } + unordered_set(unordered_set&& rhs) noexcept : ht_(mystl::move(rhs.ht_)) { + } + + unordered_set& operator=(const unordered_set& rhs) { + ht_ = rhs.ht_; + return *this; + } + + unordered_set& operator=(unordered_set&& rhs) { + ht_ = mystl::move(rhs.ht_); + return *this; + } - unordered_set &operator=(std::initializer_list ilist) { - ht_.clear(); - ht_.reserve(ilist.size()); - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_unique_noresize(*first); - return *this; + unordered_set& operator=(std::initializer_list ilist) { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_unique_noresize(*first); } + return *this; + } - ~unordered_set() = default; + ~unordered_set() = default; - // 迭代器相关 + // 迭代器相关 - iterator begin() noexcept { - return ht_.begin(); - } - const_iterator begin() const noexcept { - return ht_.begin(); - } - iterator end() noexcept { - return ht_.end(); - } - const_iterator end() const noexcept { - return ht_.end(); - } + iterator begin() noexcept { + return ht_.begin(); + } - const_iterator cbegin() const noexcept { - return ht_.cbegin(); - } - const_iterator cend() const noexcept { - return ht_.cend(); - } + const_iterator begin() const noexcept { + return ht_.begin(); + } - // 容量相关 + iterator end() noexcept { + return ht_.end(); + } - bool empty() const noexcept { - return ht_.empty(); - } - size_type size() const noexcept { - return ht_.size(); - } - size_type max_size() const noexcept { - return ht_.max_size(); - } + const_iterator end() const noexcept { + return ht_.end(); + } - // 修改容器操作 + const_iterator cbegin() const noexcept { + return ht_.cbegin(); + } - // empalce / empalce_hint + const_iterator cend() const noexcept { + return ht_.cend(); + } - template - pair emplace(Args &&...args) { - return ht_.emplace_unique(mystl::forward(args)...); - } + // 容量相关 - template - iterator emplace_hint(const_iterator hint, Args &&...args) { - return ht_.emplace_unique_use_hint(hint, - mystl::forward(args)...); - } + bool empty() const noexcept { + return ht_.empty(); + } - // insert + size_type size() const noexcept { + return ht_.size(); + } - pair insert(const value_type &value) { - return ht_.insert_unique(value); - } - pair insert(value_type &&value) { - return ht_.emplace_unique(mystl::move(value)); - } + size_type max_size() const noexcept { + return ht_.max_size(); + } - iterator insert(const_iterator hint, const value_type &value) { - return ht_.insert_unique_use_hint(hint, value); - } - iterator insert(const_iterator hint, value_type &&value) { - return ht_.emplace_unique_use_hint(hint, mystl::move(value)); - } + // 修改容器操作 - template - void insert(InputIterator first, InputIterator last) { - ht_.insert_unique(first, last); - } + // empalce / empalce_hint - // erase / clear + template + pair emplace(Args&&... args) { + return ht_.emplace_unique(mystl::forward(args)...); + } - void erase(iterator it) { - ht_.erase(it); - } - void erase(iterator first, iterator last) { - ht_.erase(first, last); - } + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return ht_.emplace_unique_use_hint(hint, mystl::forward(args)...); + } - size_type erase(const key_type &key) { - return ht_.erase_unique(key); - } + // insert - void clear() { - ht_.clear(); - } + pair insert(const value_type& value) { + return ht_.insert_unique(value); + } - void swap(unordered_set &other) noexcept { - ht_.swap(other.ht_); - } + pair insert(value_type&& value) { + return ht_.emplace_unique(mystl::move(value)); + } - // 查找相关 + iterator insert(const_iterator hint, const value_type& value) { + return ht_.insert_unique_use_hint(hint, value); + } - size_type count(const key_type &key) const { - return ht_.count(key); - } + iterator insert(const_iterator hint, value_type&& value) { + return ht_.emplace_unique_use_hint(hint, mystl::move(value)); + } - iterator find(const key_type &key) { - return ht_.find(key); - } - const_iterator find(const key_type &key) const { - return ht_.find(key); - } + template + void insert(InputIterator first, InputIterator last) { + ht_.insert_unique(first, last); + } - pair equal_range(const key_type &key) { - return ht_.equal_range_unique(key); - } - pair - equal_range(const key_type &key) const { - return ht_.equal_range_unique(key); - } + // erase / clear - // bucket interface + void erase(iterator it) { + ht_.erase(it); + } - local_iterator begin(size_type n) noexcept { - return ht_.begin(n); - } - const_local_iterator begin(size_type n) const noexcept { - return ht_.begin(n); - } - const_local_iterator cbegin(size_type n) const noexcept { - return ht_.cbegin(n); - } + void erase(iterator first, iterator last) { + ht_.erase(first, last); + } - local_iterator end(size_type n) noexcept { - return ht_.end(n); - } - const_local_iterator end(size_type n) const noexcept { - return ht_.end(n); - } - const_local_iterator cend(size_type n) const noexcept { - return ht_.cend(n); - } + size_type erase(const key_type& key) { + return ht_.erase_unique(key); + } - size_type bucket_count() const noexcept { - return ht_.bucket_count(); - } - size_type max_bucket_count() const noexcept { - return ht_.max_bucket_count(); - } + void clear() { + ht_.clear(); + } - size_type bucket_size(size_type n) const noexcept { - return ht_.bucket_size(n); - } - size_type bucket(const key_type &key) const { - return ht_.bucket(key); - } + void swap(unordered_set& other) noexcept { + ht_.swap(other.ht_); + } - // hash policy + // 查找相关 - float load_factor() const noexcept { - return ht_.load_factor(); - } + size_type count(const key_type& key) const { + return ht_.count(key); + } - float max_load_factor() const noexcept { - return ht_.max_load_factor(); - } - void max_load_factor(float ml) { - ht_.max_load_factor(ml); - } + iterator find(const key_type& key) { + return ht_.find(key); + } - void rehash(size_type count) { - ht_.rehash(count); - } - void reserve(size_type count) { - ht_.reserve(count); - } + const_iterator find(const key_type& key) const { + return ht_.find(key); + } - hasher hash_fcn() const { - return ht_.hash_fcn(); - } - key_equal key_eq() const { - return ht_.key_eq(); - } + pair equal_range(const key_type& key) { + return ht_.equal_range_unique(key); + } - public: - friend bool operator==(const unordered_set &lhs, - const unordered_set &rhs) { - return lhs.ht_.equal_range_unique(rhs.ht_); - } - friend bool operator!=(const unordered_set &lhs, - const unordered_set &rhs) { - return !lhs.ht_.equal_range_unique(rhs.ht_); - } - }; - - // 重载比较操作符 - template - bool operator==(const unordered_set &lhs, - const unordered_set &rhs) { - return lhs == rhs; - } - - template - bool operator!=(const unordered_set &lhs, - const unordered_set &rhs) { - return lhs != rhs; - } - - // 重载 mystl 的 swap - template - void swap(unordered_set &lhs, - unordered_set &rhs) { - lhs.swap(rhs); - } - - /*****************************************************************************************/ - - // 模板类 unordered_multiset,键值允许重复 - // 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash, - // 参数三代表键值比较方式,缺省使用 mystl::equal_to - template , - class KeyEqual = mystl::equal_to> - class unordered_multiset { - private: - // 使用 hashtable 作为底层机制 - typedef hashtable base_type; - base_type ht_; - - public: - // 使用 hashtable 的型别 - typedef typename base_type::allocator_type allocator_type; - typedef typename base_type::key_type key_type; - typedef typename base_type::value_type value_type; - typedef typename base_type::hasher hasher; - typedef typename base_type::key_equal key_equal; - - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; - - typedef typename base_type::const_iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::const_local_iterator local_iterator; - typedef typename base_type::const_local_iterator const_local_iterator; - - allocator_type get_allocator() const { - return ht_.get_allocator(); - } + pair + equal_range(const key_type& key) const { + return ht_.equal_range_unique(key); + } - public: - // 构造、复制、移动函数 + // bucket interface - unordered_multiset() : ht_(100, Hash(), KeyEqual()) { - } + local_iterator begin(size_type n) noexcept { + return ht_.begin(n); + } - explicit unordered_multiset(size_type bucket_count, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(bucket_count, hash, equal) { - } + const_local_iterator begin(size_type n) const noexcept { + return ht_.begin(n); + } - template - unordered_multiset(InputIterator first, InputIterator last, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual &equal = KeyEqual()) - : ht_(mystl::max(bucket_count, static_cast( - mystl::distance(first, last))), - hash, equal) { - for (; first != last; ++first) - ht_.insert_multi_noresize(*first); - } + const_local_iterator cbegin(size_type n) const noexcept { + return ht_.cbegin(n); + } - unordered_multiset(std::initializer_list ilist, - const size_type bucket_count = 100, - const Hash & hash = Hash(), - const KeyEqual & equal = KeyEqual()) - : ht_(mystl::max(bucket_count, - static_cast(ilist.size())), - hash, equal) { - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_multi_noresize(*first); - } + local_iterator end(size_type n) noexcept { + return ht_.end(n); + } - unordered_multiset(const unordered_multiset &rhs) : ht_(rhs.ht_) { - } - unordered_multiset(unordered_multiset &&rhs) noexcept - : ht_(mystl::move(rhs.ht_)) { - } + const_local_iterator end(size_type n) const noexcept { + return ht_.end(n); + } - unordered_multiset &operator=(const unordered_multiset &rhs) { - ht_ = rhs.ht_; - return *this; - } - unordered_multiset &operator=(unordered_multiset &&rhs) { - ht_ = mystl::move(rhs.ht_); - return *this; - } + const_local_iterator cend(size_type n) const noexcept { + return ht_.cend(n); + } - unordered_multiset &operator=(std::initializer_list ilist) { - ht_.clear(); - ht_.reserve(ilist.size()); - for (auto first = ilist.begin(), last = ilist.end(); first != last; - ++first) - ht_.insert_multi_noresize(*first); - return *this; - } + size_type bucket_count() const noexcept { + return ht_.bucket_count(); + } - ~unordered_multiset() = default; + size_type max_bucket_count() const noexcept { + return ht_.max_bucket_count(); + } - // 迭代器相关 + size_type bucket_size(size_type n) const noexcept { + return ht_.bucket_size(n); + } - iterator begin() noexcept { - return ht_.begin(); - } - const_iterator begin() const noexcept { - return ht_.begin(); - } - iterator end() noexcept { - return ht_.end(); - } - const_iterator end() const noexcept { - return ht_.end(); - } + size_type bucket(const key_type& key) const { + return ht_.bucket(key); + } - const_iterator cbegin() const noexcept { - return ht_.cbegin(); - } - const_iterator cend() const noexcept { - return ht_.cend(); - } + // hash policy - // 容量相关 + float load_factor() const noexcept { + return ht_.load_factor(); + } - bool empty() const noexcept { - return ht_.empty(); - } - size_type size() const noexcept { - return ht_.size(); - } - size_type max_size() const noexcept { - return ht_.max_size(); - } + float max_load_factor() const noexcept { + return ht_.max_load_factor(); + } - // 修改容器相关 + void max_load_factor(float ml) { + ht_.max_load_factor(ml); + } - // emplace / emplace_hint + void rehash(size_type count) { + ht_.rehash(count); + } - template - iterator emplace(Args &&...args) { - return ht_.emplace_multi(mystl::forward(args)...); - } + void reserve(size_type count) { + ht_.reserve(count); + } - template - iterator emplace_hint(const_iterator hint, Args &&...args) { - return ht_.emplace_multi_use_hint(hint, - mystl::forward(args)...); - } + hasher hash_fcn() const { + return ht_.hash_fcn(); + } - // insert + key_equal key_eq() const { + return ht_.key_eq(); + } - iterator insert(const value_type &value) { - return ht_.insert_multi(value); - } - iterator insert(value_type &&value) { - return ht_.emplace_multi(mystl::move(value)); - } +public: + friend bool operator==(const unordered_set& lhs, const unordered_set& rhs) { + return lhs.ht_.equal_range_unique(rhs.ht_); + } - iterator insert(const_iterator hint, const value_type &value) { - return ht_.insert_multi_use_hint(hint, value); - } - iterator insert(const_iterator hint, value_type &&value) { - return ht_.emplace_multi_use_hint(hint, mystl::move(value)); - } + friend bool operator!=(const unordered_set& lhs, const unordered_set& rhs) { + return !lhs.ht_.equal_range_unique(rhs.ht_); + } +}; - template - void insert(InputIterator first, InputIterator last) { - ht_.insert_multi(first, last); - } +// 重载比较操作符 +template +bool operator==(const unordered_set& lhs, + const unordered_set& rhs) { + return lhs == rhs; +} + +template +bool operator!=(const unordered_set& lhs, + const unordered_set& rhs) { + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_set& lhs, + unordered_set& rhs) { + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 unordered_multiset,键值允许重复 +// 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash, +// 参数三代表键值比较方式,缺省使用 mystl::equal_to +template , + class KeyEqual = mystl::equal_to> +class unordered_multiset { +private: + // 使用 hashtable 作为底层机制 + typedef hashtable base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { + return ht_.get_allocator(); + } - // erase / clear +public: + // 构造、复制、移动函数 - void erase(iterator it) { - ht_.erase(it); - } - void erase(iterator first, iterator last) { - ht_.erase(first, last); - } + unordered_multiset() : ht_(100, Hash(), KeyEqual()) { + } - size_type erase(const key_type &key) { - return ht_.erase_multi(key); - } + explicit unordered_multiset(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(bucket_count, hash, equal) { + } - void clear() { - ht_.clear(); + template + unordered_multiset(InputIterator first, InputIterator last, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, + static_cast(mystl::distance(first, last))), + hash, equal) { + for (; first != last; ++first) { + ht_.insert_multi_noresize(*first); } + } - void swap(unordered_multiset &other) noexcept { - ht_.swap(other.ht_); + unordered_multiset(std::initializer_list ilist, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, static_cast(ilist.size())), + hash, equal) { + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_multi_noresize(*first); } + } - // 查找相关 + unordered_multiset(const unordered_multiset& rhs) : ht_(rhs.ht_) { + } - size_type count(const key_type &key) const { - return ht_.count(key); - } + unordered_multiset(unordered_multiset&& rhs) noexcept + : ht_(mystl::move(rhs.ht_)) { + } - iterator find(const key_type &key) { - return ht_.find(key); - } - const_iterator find(const key_type &key) const { - return ht_.find(key); - } + unordered_multiset& operator=(const unordered_multiset& rhs) { + ht_ = rhs.ht_; + return *this; + } - pair equal_range(const key_type &key) { - return ht_.equal_range_multi(key); - } - pair - equal_range(const key_type &key) const { - return ht_.equal_range_multi(key); + unordered_multiset& operator=(unordered_multiset&& rhs) { + ht_ = mystl::move(rhs.ht_); + return *this; + } + + unordered_multiset& operator=(std::initializer_list ilist) { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; + ++first) { + ht_.insert_multi_noresize(*first); } + return *this; + } - // bucket interface + ~unordered_multiset() = default; - local_iterator begin(size_type n) noexcept { - return ht_.begin(n); - } - const_local_iterator begin(size_type n) const noexcept { - return ht_.begin(n); - } - const_local_iterator cbegin(size_type n) const noexcept { - return ht_.cbegin(n); - } + // 迭代器相关 - local_iterator end(size_type n) noexcept { - return ht_.end(n); - } - const_local_iterator end(size_type n) const noexcept { - return ht_.end(n); - } - const_local_iterator cend(size_type n) const noexcept { - return ht_.cend(n); - } + iterator begin() noexcept { + return ht_.begin(); + } - size_type bucket_count() const noexcept { - return ht_.bucket_count(); - } - size_type max_bucket_count() const noexcept { - return ht_.max_bucket_count(); - } + const_iterator begin() const noexcept { + return ht_.begin(); + } - size_type bucket_size(size_type n) const noexcept { - return ht_.bucket_size(n); - } - size_type bucket(const key_type &key) const { - return ht_.bucket(key); - } + iterator end() noexcept { + return ht_.end(); + } - // hash policy + const_iterator end() const noexcept { + return ht_.end(); + } - float load_factor() const noexcept { - return ht_.load_factor(); - } + const_iterator cbegin() const noexcept { + return ht_.cbegin(); + } - float max_load_factor() const noexcept { - return ht_.max_load_factor(); - } - void max_load_factor(float ml) { - ht_.max_load_factor(ml); - } + const_iterator cend() const noexcept { + return ht_.cend(); + } - void rehash(size_type count) { - ht_.rehash(count); - } - void reserve(size_type count) { - ht_.reserve(count); - } + // 容量相关 - hasher hash_fcn() const { - return ht_.hash_fcn(); - } - key_equal key_eq() const { - return ht_.key_eq(); - } + bool empty() const noexcept { + return ht_.empty(); + } - public: - friend bool operator==(const unordered_multiset &lhs, - const unordered_multiset &rhs) { - return lhs.ht_.equal_range_multi(rhs.ht_); - } - friend bool operator!=(const unordered_multiset &lhs, - const unordered_multiset &rhs) { - return !lhs.ht_.equal_range_multi(rhs.ht_); - } - }; + size_type size() const noexcept { + return ht_.size(); + } + + size_type max_size() const noexcept { + return ht_.max_size(); + } + + // 修改容器相关 + + // emplace / emplace_hint + + template + iterator emplace(Args&&... args) { + return ht_.emplace_multi(mystl::forward(args)...); + } + + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return ht_.emplace_multi_use_hint(hint, mystl::forward(args)...); + } + + // insert + + iterator insert(const value_type& value) { + return ht_.insert_multi(value); + } + + iterator insert(value_type&& value) { + return ht_.emplace_multi(mystl::move(value)); + } + + iterator insert(const_iterator hint, const value_type& value) { + return ht_.insert_multi_use_hint(hint, value); + } + + iterator insert(const_iterator hint, value_type&& value) { + return ht_.emplace_multi_use_hint(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) { + ht_.insert_multi(first, last); + } + + // erase / clear + + void erase(iterator it) { + ht_.erase(it); + } + + void erase(iterator first, iterator last) { + ht_.erase(first, last); + } + + size_type erase(const key_type& key) { + return ht_.erase_multi(key); + } + + void clear() { + ht_.clear(); + } + + void swap(unordered_multiset& other) noexcept { + ht_.swap(other.ht_); + } + + // 查找相关 + + size_type count(const key_type& key) const { + return ht_.count(key); + } + + iterator find(const key_type& key) { + return ht_.find(key); + } + + const_iterator find(const key_type& key) const { + return ht_.find(key); + } + + pair equal_range(const key_type& key) { + return ht_.equal_range_multi(key); + } + + pair + equal_range(const key_type& key) const { + return ht_.equal_range_multi(key); + } + + // bucket interface - // 重载比较操作符 - template - bool operator==(const unordered_multiset &lhs, - const unordered_multiset &rhs) { - return lhs == rhs; + local_iterator begin(size_type n) noexcept { + return ht_.begin(n); } - template - bool operator!=(const unordered_multiset &lhs, - const unordered_multiset &rhs) { - return lhs != rhs; + const_local_iterator begin(size_type n) const noexcept { + return ht_.begin(n); } - // 重载 mystl 的 swap - template - void swap(unordered_multiset &lhs, - unordered_multiset &rhs) { - lhs.swap(rhs); + const_local_iterator cbegin(size_type n) const noexcept { + return ht_.cbegin(n); } + local_iterator end(size_type n) noexcept { + return ht_.end(n); + } + + const_local_iterator end(size_type n) const noexcept { + return ht_.end(n); + } + + const_local_iterator cend(size_type n) const noexcept { + return ht_.cend(n); + } + + size_type bucket_count() const noexcept { + return ht_.bucket_count(); + } + + size_type max_bucket_count() const noexcept { + return ht_.max_bucket_count(); + } + + size_type bucket_size(size_type n) const noexcept { + return ht_.bucket_size(n); + } + + size_type bucket(const key_type& key) const { + return ht_.bucket(key); + } + + // hash policy + + float load_factor() const noexcept { + return ht_.load_factor(); + } + + float max_load_factor() const noexcept { + return ht_.max_load_factor(); + } + + void max_load_factor(float ml) { + ht_.max_load_factor(ml); + } + + void rehash(size_type count) { + ht_.rehash(count); + } + + void reserve(size_type count) { + ht_.reserve(count); + } + + hasher hash_fcn() const { + return ht_.hash_fcn(); + } + + key_equal key_eq() const { + return ht_.key_eq(); + } + +public: + friend bool + operator==(const unordered_multiset& lhs, const unordered_multiset& rhs) { + return lhs.ht_.equal_range_multi(rhs.ht_); + } + + friend bool + operator!=(const unordered_multiset& lhs, const unordered_multiset& rhs) { + return !lhs.ht_.equal_range_multi(rhs.ht_); + } }; -#endif /* _UNORDERED_SET_ */ +// 重载比较操作符 +template +bool operator==(const unordered_multiset& lhs, + const unordered_multiset& rhs) { + return lhs == rhs; +} + +template +bool operator!=(const unordered_multiset& lhs, + const unordered_multiset& rhs) { + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_multiset& lhs, + unordered_multiset& rhs) { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_UNORDERED_SET */ diff --git a/src/libcxx/include/util b/src/libcxx/include/util index 3da3ed42f..ddd668f36 100644 --- a/src/libcxx/include/util +++ b/src/libcxx/include/util @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// util for Simple-XX/SimpleKernel. - -#ifndef _UTIL_ -#define _UTIL_ +/** + * @file util + * @brief stl util 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_UTIL +#define SIMPLEKERNEL_UTIL // 这个文件包含一些通用工具,包括 move, forward, swap 等函数,以及 pair 等 @@ -14,262 +25,268 @@ namespace mystl { - // move +// move - template - typename std::remove_reference::type &&move(T &&arg) noexcept { - return static_cast::type &&>(arg); - } +template +typename std::remove_reference::type&& move(T&& arg) noexcept { + return static_cast::type&&>(arg); +} - // forward +// forward - template - T &&forward(typename std::remove_reference::type &arg) noexcept { - return static_cast(arg); - } +template +T&& forward(typename std::remove_reference::type& arg) noexcept { + return static_cast(arg); +} - template - T &&forward(typename std::remove_reference::type &&arg) noexcept { - static_assert(!std::is_lvalue_reference::value, "bad forward"); - return static_cast(arg); - } +template +T&& forward(typename std::remove_reference::type&& arg) noexcept { + static_assert(!std::is_lvalue_reference::value, "bad forward"); + return static_cast(arg); +} - // swap +// swap - template - void swap(Tp &lhs, Tp &rhs) { - auto tmp(mystl::move(lhs)); - lhs = mystl::move(rhs); - rhs = mystl::move(tmp); - } +template +void swap(Tp& lhs, Tp& rhs) { + auto tmp(mystl::move(lhs)); + lhs = mystl::move(rhs); + rhs = mystl::move(tmp); +} - template - ForwardIter2 swap_range(ForwardIter1 first1, ForwardIter1 last1, - ForwardIter2 first2) { - for (; first1 != last1; ++first1, (void)++first2) - mystl::swap(*first1, *first2); - return first2; +template +ForwardIter2 +swap_range(ForwardIter1 first1, ForwardIter1 last1, ForwardIter2 first2) { + for (; first1 != last1; ++first1, (void)++first2) { + mystl::swap(*first1, *first2); } - - template - void swap(Tp (&a)[N], Tp (&b)[N]) { - mystl::swap_range(a, a + N, b); + return first2; +} + +template +void swap(Tp (&a)[N], Tp (&b)[N]) { + mystl::swap_range(a, a + N, b); +} + +// -------------------------------------------------------------------------------------- +// pair + +// 结构体模板 : pair +// 两个模板参数分别表示两个数据的类型 +// 用 first 和 second 来分别取出第一个数据和第二个数据 +template +struct pair { + typedef Ty1 first_type; + typedef Ty2 second_type; + + first_type first; // 保存第一个数据 + second_type second; // 保存第二个数据 + + // default constructiable + template ::value + && std::is_default_constructible::value, + void>::type> + constexpr pair() : first(), second() { } - // -------------------------------------------------------------------------------------- - // pair - - // 结构体模板 : pair - // 两个模板参数分别表示两个数据的类型 - // 用 first 和 second 来分别取出第一个数据和第二个数据 - template - struct pair { - typedef Ty1 first_type; - typedef Ty2 second_type; - - first_type first; // 保存第一个数据 - second_type second; // 保存第二个数据 - - // default constructiable - template ::value && - std::is_default_constructible::value, - void>::type> - constexpr pair() : first(), second() { - } - - // implicit constructiable for this type - template ::value && - std::is_copy_constructible::value && - std::is_convertible::value && - std::is_convertible::value, - int>::type = 0> - constexpr pair(const Ty1 &a, const Ty2 &b) : first(a), second(b) { - } - - // explicit constructible for this type - template ::value && - std::is_copy_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), - int>::type = 0> - explicit constexpr pair(const Ty1 &a, const Ty2 &b) - : first(a), second(b) { - } - - pair(const pair &rhs) = default; - pair(pair &&rhs) = default; - - // implicit constructiable for other type - template ::value && - std::is_constructible::value && - std::is_convertible::value && - std::is_convertible::value, - int>::type = 0> - constexpr pair(Other1 &&a, Other2 &&b) - : first(mystl::forward(a)), - second(mystl::forward(b)) { - } - - // explicit constructiable for other type - template ::value && - std::is_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), - int>::type = 0> - explicit constexpr pair(Other1 &&a, Other2 &&b) - : first(mystl::forward(a)), - second(mystl::forward(b)) { - } - - // implicit constructiable for other pair - template ::value && - std::is_constructible::value && - std::is_convertible::value && - std::is_convertible::value, - int>::type = 0> - constexpr pair(const pair &other) - : first(other.first), second(other.second) { - } - - // explicit constructiable for other pair - template ::value && - std::is_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), - int>::type = 0> - explicit constexpr pair(const pair &other) - : first(other.first), second(other.second) { - } - - // implicit constructiable for other pair - template ::value && - std::is_constructible::value && - std::is_convertible::value && - std::is_convertible::value, - int>::type = 0> - constexpr pair(pair &&other) - : first(mystl::forward(other.first)), - second(mystl::forward(other.second)) { - } - - // explicit constructiable for other pair - template ::value && - std::is_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), - int>::type = 0> - explicit constexpr pair(pair &&other) - : first(mystl::forward(other.first)), - second(mystl::forward(other.second)) { - } - - // copy assign for this pair - pair &operator=(const pair &rhs) { - if (this != &rhs) { - first = rhs.first; - second = rhs.second; - } - return *this; - } - - // move assign for this pair - pair &operator=(pair &&rhs) { - if (this != &rhs) { - first = mystl::move(rhs.first); - second = mystl::move(rhs.second); - } - return *this; - } - - // copy assign for other pair - template - pair &operator=(const pair &other) { - first = other.first; - second = other.second; - return *this; - } + // implicit constructiable for this type + template < + class U1 = Ty1, class U2 = Ty2, + typename std::enable_if::value + && std::is_copy_constructible::value + && std::is_convertible::value + && std::is_convertible::value, + int>::type + = 0> + constexpr pair(const Ty1& a, const Ty2& b) : first(a), second(b) { + } - // move assign for other pair - template - pair &operator=(pair &&other) { - first = mystl::forward(other.first); - second = mystl::forward(other.second); - return *this; - } + // explicit constructible for this type + template ::value + && std::is_copy_constructible::value + && (!std::is_convertible::value + || !std::is_convertible::value), + int>::type + = 0> + explicit constexpr pair(const Ty1& a, const Ty2& b) : first(a), second(b) { + } - ~pair() = default; + pair(const pair& rhs) = default; + pair(pair&& rhs) = default; + + // implicit constructiable for other type + template < + class Other1, class Other2, + typename std::enable_if::value + && std::is_constructible::value + && std::is_convertible::value + && std::is_convertible::value, + int>::type + = 0> + constexpr pair(Other1&& a, Other2&& b) + : first(mystl::forward(a)), second(mystl::forward(b)) { + } - void swap(pair &other) { - if (this != &other) { - mystl::swap(first, other.first); - mystl::swap(second, other.second); - } - } - }; + // explicit constructiable for other type + template ::value + && std::is_constructible::value + && (!std::is_convertible::value + || !std::is_convertible::value), + int>::type + = 0> + explicit constexpr pair(Other1&& a, Other2&& b) + : first(mystl::forward(a)), second(mystl::forward(b)) { + } - // 重载比较操作符 - template - bool operator==(const pair &lhs, const pair &rhs) { - return lhs.first == rhs.first && lhs.second == rhs.second; + // implicit constructiable for other pair + template ::value + && std::is_constructible::value + && std::is_convertible::value + && std::is_convertible::value, + int>::type + = 0> + constexpr pair(const pair& other) + : first(other.first), second(other.second) { } - template - bool operator<(const pair &lhs, const pair &rhs) { - return lhs.first < rhs.first || - (lhs.first == rhs.first && lhs.second < rhs.second); + // explicit constructiable for other pair + template ::value + && std::is_constructible::value + && (!std::is_convertible::value + || !std::is_convertible::value), + int>::type + = 0> + explicit constexpr pair(const pair& other) + : first(other.first), second(other.second) { } - template - bool operator!=(const pair &lhs, const pair &rhs) { - return !(lhs == rhs); + // implicit constructiable for other pair + template < + class Other1, class Other2, + typename std::enable_if::value + && std::is_constructible::value + && std::is_convertible::value + && std::is_convertible::value, + int>::type + = 0> + constexpr pair(pair&& other) + : first(mystl::forward(other.first)), + second(mystl::forward(other.second)) { } - template - bool operator>(const pair &lhs, const pair &rhs) { - return rhs < lhs; + // explicit constructiable for other pair + template ::value + && std::is_constructible::value + && (!std::is_convertible::value + || !std::is_convertible::value), + int>::type + = 0> + explicit constexpr pair(pair&& other) + : first(mystl::forward(other.first)), + second(mystl::forward(other.second)) { } - template - bool operator<=(const pair &lhs, const pair &rhs) { - return !(rhs < lhs); + // copy assign for this pair + pair& operator=(const pair& rhs) { + if (this != &rhs) { + first = rhs.first; + second = rhs.second; + } + return *this; } - template - bool operator>=(const pair &lhs, const pair &rhs) { - return !(lhs < rhs); + // move assign for this pair + pair& operator=(pair&& rhs) { + if (this != &rhs) { + first = mystl::move(rhs.first); + second = mystl::move(rhs.second); + } + return *this; } - // 重载 mystl 的 swap - template - void swap(pair &lhs, pair &rhs) { - lhs.swap(rhs); + // copy assign for other pair + template + pair& operator=(const pair& other) { + first = other.first; + second = other.second; + return *this; } - // 全局函数,让两个数据成为一个 pair - template - pair make_pair(Ty1 &&first, Ty2 &&second) { - return pair(mystl::forward(first), - mystl::forward(second)); + // move assign for other pair + template + pair& operator=(pair&& other) { + first = mystl::forward(other.first); + second = mystl::forward(other.second); + return *this; } + ~pair() = default; + + void swap(pair& other) { + if (this != &other) { + mystl::swap(first, other.first); + mystl::swap(second, other.second); + } + } }; -#endif /* _UTIL_ */ +// 重载比较操作符 +template +bool operator==(const pair& lhs, const pair& rhs) { + return lhs.first == rhs.first && lhs.second == rhs.second; +} + +template +bool operator<(const pair& lhs, const pair& rhs) { + return lhs.first < rhs.first + || (lhs.first == rhs.first && lhs.second < rhs.second); +} + +template +bool operator!=(const pair& lhs, const pair& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const pair& lhs, const pair& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const pair& lhs, const pair& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const pair& lhs, const pair& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(pair& lhs, pair& rhs) { + lhs.swap(rhs); +} + +// 全局函数,让两个数据成为一个 pair +template +pair make_pair(Ty1&& first, Ty2&& second) { + return pair(mystl::forward(first), + mystl::forward(second)); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_UTIL */ diff --git a/src/libcxx/include/vector b/src/libcxx/include/vector index 20e0d1330..3b0b3d801 100644 --- a/src/libcxx/include/vector +++ b/src/libcxx/include/vector @@ -1,11 +1,22 @@  -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/Alinshans/MyTinySTL -// vector for Simple-XX/SimpleKernel. - -#ifndef _VECTOR_ -#define _VECTOR_ +/** + * @file vector + * @brief stl vector 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-04-05 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/Alinshans/MyTinySTL + * @par change log: + * + *
DateAuthorDescription + *
2023-04-05Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_VECTOR +#define SIMPLEKERNEL_VECTOR // 这个头文件包含一个模板类 vector // vector : 向量 @@ -13,7 +24,7 @@ // notes: // // 异常保证: -// std::vecotr +// std::vector // 满足基本异常保证,部分函数无异常保证,并对以下函数做强异常安全保证: // * emplace // * emplace_back @@ -24,848 +35,870 @@ // * resize // * insert -#include "initializer_list" #include "algo" +#include "exceptdef" +#include "initializer_list" #include "iterator" #include "memory" #include "util" -#include "exceptdef" namespace mystl { #ifdef max -#pragma message("#undefing marco max") -#undef max -#endif // max +# pragma message("#undefing marco max") +# undef max +#endif // max #ifdef min -#pragma message("#undefing marco min") -#undef min -#endif // min - - // 模板类: vector - // 模板参数 T 代表类型 - template - class vector { - static_assert(!std::is_same::value, - "vector is abandoned in mystl"); - - public: - // vector 的嵌套型别定义 - typedef mystl::allocator allocator_type; - typedef mystl::allocator data_allocator; - - typedef typename allocator_type::value_type value_type; - typedef typename allocator_type::pointer pointer; - typedef typename allocator_type::const_pointer const_pointer; - typedef typename allocator_type::reference reference; - typedef typename allocator_type::const_reference const_reference; - typedef typename allocator_type::size_type size_type; - typedef typename allocator_type::difference_type difference_type; - - typedef value_type * iterator; - typedef const value_type * const_iterator; - typedef mystl::reverse_iterator reverse_iterator; - typedef mystl::reverse_iterator const_reverse_iterator; - - allocator_type get_allocator() { - return data_allocator(); - } +# pragma message("#undefing marco min") +# undef min +#endif // min - private: - iterator begin_; // 表示目前使用空间的头部 - iterator end_; // 表示目前使用空间的尾部 - iterator cap_; // 表示目前储存空间的尾部 +// 模板类: vector +// 模板参数 T 代表类型 +template +class vector { + static_assert(!std::is_same::value, + "vector is abandoned in mystl"); - public: - // 构造、复制、移动、析构函数 - vector() noexcept { - try_init(); - } +public: + // vector 的嵌套型别定义 + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; - explicit vector(size_type n) { - fill_init(n, value_type()); - } + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; - vector(size_type n, const value_type &value) { - fill_init(n, value); - } - - template ::value, - int>::type = 0> - vector(Iter first, Iter last) { - MYSTL_DEBUG(!(last < first)); - range_init(first, last); - } + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; - vector(const vector &rhs) { - range_init(rhs.begin_, rhs.end_); - } + allocator_type get_allocator() { + return data_allocator(); + } - vector(vector &&rhs) noexcept - : begin_(rhs.begin_), end_(rhs.end_), cap_(rhs.cap_) { - rhs.begin_ = nullptr; - rhs.end_ = nullptr; - rhs.cap_ = nullptr; - } +private: + iterator begin_; // 表示目前使用空间的头部 + iterator end_; // 表示目前使用空间的尾部 + iterator cap_; // 表示目前储存空间的尾部 - vector(std::initializer_list ilist) { - range_init(ilist.begin(), ilist.end()); - } +public: + // 构造、复制、移动、析构函数 + vector() noexcept { + try_init(); + } - vector &operator=(const vector &rhs); - vector &operator=(vector &&rhs) noexcept; + explicit vector(size_type n) { + fill_init(n, value_type()); + } - vector &operator=(std::initializer_list ilist) { - vector tmp(ilist.begin(), ilist.end()); - swap(tmp); - return *this; - } + vector(size_type n, const value_type& value) { + fill_init(n, value); + } - ~vector() { - destroy_and_recover(begin_, end_, cap_ - begin_); - begin_ = end_ = cap_ = nullptr; - } + template ::value, int>::type + = 0> + vector(Iter first, Iter last) { + MYSTL_DEBUG(!(last < first)); + range_init(first, last); + } - public: - // 迭代器相关操作 - iterator begin() noexcept { - return begin_; - } - const_iterator begin() const noexcept { - return begin_; - } - iterator end() noexcept { - return end_; - } - const_iterator end() const noexcept { - return end_; - } + vector(const vector& rhs) { + range_init(rhs.begin_, rhs.end_); + } - reverse_iterator rbegin() noexcept { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - reverse_iterator rend() noexcept { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } + vector(vector&& rhs) noexcept + : begin_(rhs.begin_), end_(rhs.end_), cap_(rhs.cap_) { + rhs.begin_ = nullptr; + rhs.end_ = nullptr; + rhs.cap_ = nullptr; + } - const_iterator cbegin() const noexcept { - return begin(); - } - const_iterator cend() const noexcept { - return end(); - } - const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - const_reverse_iterator crend() const noexcept { - return rend(); - } + vector(std::initializer_list ilist) { + range_init(ilist.begin(), ilist.end()); + } - // 容量相关操作 - bool empty() const noexcept { - return begin_ == end_; - } - size_type size() const noexcept { - return static_cast(end_ - begin_); - } - size_type max_size() const noexcept { - return static_cast(-1) / sizeof(T); - } - size_type capacity() const noexcept { - return static_cast(cap_ - begin_); - } - void reserve(size_type n); - void shrink_to_fit(); + vector& operator=(const vector& rhs); + vector& operator=(vector&& rhs) noexcept; - // 访问元素相关操作 - reference operator[](size_type n) { - MYSTL_DEBUG(n < size()); - return *(begin_ + n); - } - const_reference operator[](size_type n) const { - MYSTL_DEBUG(n < size()); - return *(begin_ + n); - } - reference at(size_type n) { - THROW_OUT_OF_RANGE_IF(!(n < size()), - "vector::at() subscript out of range"); - return (*this)[n]; - } - const_reference at(size_type n) const { - THROW_OUT_OF_RANGE_IF(!(n < size()), - "vector::at() subscript out of range"); - return (*this)[n]; - } + vector& operator=(std::initializer_list ilist) { + vector tmp(ilist.begin(), ilist.end()); + swap(tmp); + return *this; + } - reference front() { - MYSTL_DEBUG(!empty()); - return *begin_; - } - const_reference front() const { - MYSTL_DEBUG(!empty()); - return *begin_; - } - reference back() { - MYSTL_DEBUG(!empty()); - return *(end_ - 1); - } - const_reference back() const { - MYSTL_DEBUG(!empty()); - return *(end_ - 1); - } + ~vector() { + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = end_ = cap_ = nullptr; + } - pointer data() noexcept { - return begin_; - } - const_pointer data() const noexcept { - return begin_; - } +public: + // 迭代器相关操作 + iterator begin() noexcept { + return begin_; + } - // 修改容器相关操作 + const_iterator begin() const noexcept { + return begin_; + } - // assign + iterator end() noexcept { + return end_; + } - void assign(size_type n, const value_type &value) { - fill_assign(n, value); - } + const_iterator end() const noexcept { + return end_; + } - template ::value, - int>::type = 0> - void assign(Iter first, Iter last) { - MYSTL_DEBUG(!(last < first)); - copy_assign(first, last, iterator_category(first)); - } + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } - void assign(std::initializer_list il) { - copy_assign(il.begin(), il.end(), mystl::forward_iterator_tag{}); - } + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } - // emplace / emplace_back + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } - template - iterator emplace(const_iterator pos, Args &&...args); + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } - template - void emplace_back(Args &&...args); + const_iterator cbegin() const noexcept { + return begin(); + } - // push_back / pop_back + const_iterator cend() const noexcept { + return end(); + } - void push_back(const value_type &value); - void push_back(value_type &&value) { - emplace_back(mystl::move(value)); - } + const_reverse_iterator crbegin() const noexcept { + return rbegin(); + } - void pop_back(); + const_reverse_iterator crend() const noexcept { + return rend(); + } - // insert + // 容量相关操作 + bool empty() const noexcept { + return begin_ == end_; + } - iterator insert(const_iterator pos, const value_type &value); - iterator insert(const_iterator pos, value_type &&value) { - return emplace(pos, mystl::move(value)); - } + size_type size() const noexcept { + return static_cast(end_ - begin_); + } - iterator insert(const_iterator pos, size_type n, - const value_type &value) { - MYSTL_DEBUG(pos >= begin() && pos <= end()); - return fill_insert(const_cast(pos), n, value); - } + size_type max_size() const noexcept { + return static_cast(-1) / sizeof(T); + } - template ::value, - int>::type = 0> - void insert(const_iterator pos, Iter first, Iter last) { - MYSTL_DEBUG(pos >= begin() && pos <= end() && !(last < first)); - copy_insert(const_cast(pos), first, last); - } + size_type capacity() const noexcept { + return static_cast(cap_ - begin_); + } - // erase / clear - iterator erase(const_iterator pos); - iterator erase(const_iterator first, const_iterator last); - void clear() { - erase(begin(), end()); - } + void reserve(size_type n); + void shrink_to_fit(); - // resize / reverse - void resize(size_type new_size) { - return resize(new_size, value_type()); - } - void resize(size_type new_size, const value_type &value); + // 访问元素相关操作 + reference operator[](size_type n) { + MYSTL_DEBUG(n < size()); + return *(begin_ + n); + } - void reverse() { - mystl::reverse(begin(), end()); - } + const_reference operator[](size_type n) const { + MYSTL_DEBUG(n < size()); + return *(begin_ + n); + } - // swap - void swap(vector &rhs) noexcept; + reference at(size_type n) { + THROW_OUT_OF_RANGE_IF(!(n < size()), + "vector::at() subscript out of range"); + return (*this)[n]; + } - private: - // helper functions + const_reference at(size_type n) const { + THROW_OUT_OF_RANGE_IF(!(n < size()), + "vector::at() subscript out of range"); + return (*this)[n]; + } - // initialize / destroy - void try_init() noexcept; + reference front() { + MYSTL_DEBUG(!empty()); + return *begin_; + } - void init_space(size_type size, size_type cap); + const_reference front() const { + MYSTL_DEBUG(!empty()); + return *begin_; + } - void fill_init(size_type n, const value_type &value); - template - void range_init(Iter first, Iter last); + reference back() { + MYSTL_DEBUG(!empty()); + return *(end_ - 1); + } - void destroy_and_recover(iterator first, iterator last, size_type n); + const_reference back() const { + MYSTL_DEBUG(!empty()); + return *(end_ - 1); + } - // calculate the growth size - size_type get_new_cap(size_type add_size); + pointer data() noexcept { + return begin_; + } - // assign + const_pointer data() const noexcept { + return begin_; + } - void fill_assign(size_type n, const value_type &value); + // 修改容器相关操作 - template - void copy_assign(IIter first, IIter last, input_iterator_tag); + // assign - template - void copy_assign(FIter first, FIter last, forward_iterator_tag); + void assign(size_type n, const value_type& value) { + fill_assign(n, value); + } - // reallocate + template ::value, int>::type + = 0> + void assign(Iter first, Iter last) { + MYSTL_DEBUG(!(last < first)); + copy_assign(first, last, iterator_category(first)); + } - template - void reallocate_emplace(iterator pos, Args &&...args); - void reallocate_insert(iterator pos, const value_type &value); + void assign(std::initializer_list il) { + copy_assign(il.begin(), il.end(), mystl::forward_iterator_tag {}); + } - // insert + // emplace / emplace_back - iterator fill_insert(iterator pos, size_type n, - const value_type &value); - template - void copy_insert(iterator pos, IIter first, IIter last); + template + iterator emplace(const_iterator pos, Args&&... args); - // shrink_to_fit + template + void emplace_back(Args&&... args); - void reinsert(size_type size); - }; + // push_back / pop_back - /*****************************************************************************************/ + void push_back(const value_type& value); - // 复制赋值操作符 - template - vector &vector::operator=(const vector &rhs) { - if (this != &rhs) { - const auto len = rhs.size(); - if (len > capacity()) { - vector tmp(rhs.begin(), rhs.end()); - swap(tmp); - } - else if (size() >= len) { - auto i = mystl::copy(rhs.begin(), rhs.end(), begin()); - data_allocator::destroy(i, end_); - end_ = begin_ + len; - } - else { - mystl::copy(rhs.begin(), rhs.begin() + size(), begin_); - mystl::uninitialized_copy(rhs.begin() + size(), rhs.end(), - end_); - cap_ = end_ = begin_ + len; - } - } - return *this; + void push_back(value_type&& value) { + emplace_back(mystl::move(value)); } - // 移动赋值操作符 - template - vector &vector::operator=(vector &&rhs) noexcept { - destroy_and_recover(begin_, end_, cap_ - begin_); - begin_ = rhs.begin_; - end_ = rhs.end_; - cap_ = rhs.cap_; - rhs.begin_ = nullptr; - rhs.end_ = nullptr; - rhs.cap_ = nullptr; - return *this; - } + void pop_back(); - // 预留空间大小,当原容量小于要求大小时,才会重新分配 - template - void vector::reserve(size_type n) { - if (capacity() < n) { - THROW_LENGTH_ERROR_IF( - n > max_size(), - "n can not larger than max_size() in vector::reserve(n)"); - const auto old_size = size(); - auto tmp = data_allocator::allocate(n); - mystl::uninitialized_move(begin_, end_, tmp); - data_allocator::deallocate(begin_, cap_ - begin_); - begin_ = tmp; - end_ = tmp + old_size; - cap_ = begin_ + n; - } - } + // insert - // 放弃多余的容量 - template - void vector::shrink_to_fit() { - if (end_ < cap_) { - reinsert(size()); - } + iterator insert(const_iterator pos, const value_type& value); + + iterator insert(const_iterator pos, value_type&& value) { + return emplace(pos, mystl::move(value)); } - // 在 pos 位置就地构造元素,避免额外的复制或移动开销 - template - template - typename vector::iterator vector::emplace(const_iterator pos, - Args &&...args) { + iterator insert(const_iterator pos, size_type n, const value_type& value) { MYSTL_DEBUG(pos >= begin() && pos <= end()); - iterator xpos = const_cast(pos); - const size_type n = xpos - begin_; - if (end_ != cap_ && xpos == end_) { - data_allocator::construct(mystl::address_of(*end_), - mystl::forward(args)...); - ++end_; - } - else if (end_ != cap_) { - auto new_end = end_; - data_allocator::construct(mystl::address_of(*end_), *(end_ - 1)); - ++new_end; - mystl::copy_backward(xpos, end_ - 1, end_); - *xpos = value_type(mystl::forward(args)...); - } - else { - reallocate_emplace(xpos, mystl::forward(args)...); - } - return begin() + n; + return fill_insert(const_cast(pos), n, value); } - // 在尾部就地构造元素,避免额外的复制或移动开销 - template - template - void vector::emplace_back(Args &&...args) { - if (end_ < cap_) { - data_allocator::construct(mystl::address_of(*end_), - mystl::forward(args)...); - ++end_; - } - else { - reallocate_emplace(end_, mystl::forward(args)...); - } + template ::value, int>::type + = 0> + void insert(const_iterator pos, Iter first, Iter last) { + MYSTL_DEBUG(pos >= begin() && pos <= end() && !(last < first)); + copy_insert(const_cast(pos), first, last); } - // 在尾部插入元素 - template - void vector::push_back(const value_type &value) { - if (end_ != cap_) { - data_allocator::construct(mystl::address_of(*end_), value); - ++end_; - } - else { - reallocate_insert(end_, value); - } - } + // erase / clear + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); - // 弹出尾部元素 - template - void vector::pop_back() { - MYSTL_DEBUG(!empty()); - data_allocator::destroy(end_ - 1); - --end_; + void clear() { + erase(begin(), end()); } - // 在 pos 处插入元素 - template - typename vector::iterator vector::insert(const_iterator pos, - const value_type &value) { - MYSTL_DEBUG(pos >= begin() && pos <= end()); - iterator xpos = const_cast(pos); - const size_type n = pos - begin_; - if (end_ != cap_ && xpos == end_) { - data_allocator::construct(mystl::address_of(*end_), value); - ++end_; - } - else if (end_ != cap_) { - auto new_end = end_; - data_allocator::construct(mystl::address_of(*end_), *(end_ - 1)); - ++new_end; - auto value_copy = value; // 避免元素因以下复制操作而被改变 - mystl::copy_backward(xpos, end_ - 1, end_); - *xpos = mystl::move(value_copy); - end_ = new_end; - } - else { - reallocate_insert(xpos, value); - } - return begin_ + n; - } - - // 删除 pos 位置上的元素 - template - typename vector::iterator vector::erase(const_iterator pos) { - MYSTL_DEBUG(pos >= begin() && pos < end()); - iterator xpos = begin_ + (pos - begin()); - mystl::move(xpos + 1, end_, xpos); - data_allocator::destroy(end_ - 1); - --end_; - return xpos; - } - - // 删除[first, last)上的元素 - template - typename vector::iterator vector::erase(const_iterator first, - const_iterator last) { - MYSTL_DEBUG(first >= begin() && last <= end() && !(last < first)); - const auto n = first - begin(); - iterator r = begin_ + (first - begin()); - data_allocator::destroy(mystl::move(r + (last - first), end_, r), end_); - end_ = end_ - (last - first); - return begin_ + n; - } - - // 重置容器大小 - template - void vector::resize(size_type new_size, const value_type &value) { - if (new_size < size()) { - erase(begin() + new_size, end()); - } - else { - insert(end(), new_size - size(), value); - } + // resize / reverse + void resize(size_type new_size) { + return resize(new_size, value_type()); } - // 与另一个 vector 交换 - template - void vector::swap(vector &rhs) noexcept { - if (this != &rhs) { - mystl::swap(begin_, rhs.begin_); - mystl::swap(end_, rhs.end_); - mystl::swap(cap_, rhs.cap_); - } + void resize(size_type new_size, const value_type& value); + + void reverse() { + mystl::reverse(begin(), end()); } - /*****************************************************************************************/ - // helper function + // swap + void swap(vector& rhs) noexcept; - // try_init 函数,若分配失败则忽略,不抛出异常 - template - void vector::try_init() noexcept { - try { - begin_ = data_allocator::allocate(16); - end_ = begin_; - cap_ = begin_ + 16; - } catch (...) { - begin_ = nullptr; - end_ = nullptr; - cap_ = nullptr; - } - } +private: + // helper functions - // init_space 函数 - template - void vector::init_space(size_type size, size_type cap) { - try { - begin_ = data_allocator::allocate(cap); - end_ = begin_ + size; - cap_ = begin_ + cap; - } catch (...) { - begin_ = nullptr; - end_ = nullptr; - cap_ = nullptr; - throw; - } - } + // initialize / destroy + void try_init() noexcept; - // fill_init 函数 - template - void vector::fill_init(size_type n, const value_type &value) { - const size_type init_size = mystl::max(static_cast(16), n); - init_space(n, init_size); - mystl::uninitialized_fill_n(begin_, n, value); - } + void init_space(size_type size, size_type cap); - // range_init 函数 - template + void fill_init(size_type n, const value_type& value); template - void vector::range_init(Iter first, Iter last) { - const size_type init_size = mystl::max( - static_cast(last - first), static_cast(16)); - init_space(static_cast(last - first), init_size); - mystl::uninitialized_copy(first, last, begin_); - } - - // destroy_and_recover 函数 - template - void vector::destroy_and_recover(iterator first, iterator last, - size_type n) { - data_allocator::destroy(first, last); - data_allocator::deallocate(first, n); - } - - // get_new_cap 函数 - template - typename vector::size_type vector::get_new_cap(size_type add_size) { - const auto old_size = capacity(); - THROW_LENGTH_ERROR_IF(old_size > max_size() - add_size, - "vector's size too big"); - if (old_size > max_size() - old_size / 2) { - return old_size + add_size > max_size() - 16 - ? old_size + add_size - : old_size + add_size + 16; - } - const size_type new_size = - old_size == 0 - ? mystl::max(add_size, static_cast(16)) - : mystl::max(old_size + old_size / 2, old_size + add_size); - return new_size; - } - - // fill_assign 函数 - template - void vector::fill_assign(size_type n, const value_type &value) { - if (n > capacity()) { - vector tmp(n, value); - swap(tmp); - } - else if (n > size()) { - mystl::fill(begin(), end(), value); - end_ = mystl::uninitialized_fill_n(end_, n - size(), value); - } - else { - erase(mystl::fill_n(begin_, n, value), end_); - } - } + void range_init(Iter first, Iter last); + + void destroy_and_recover(iterator first, iterator last, size_type n); + + // calculate the growth size + size_type get_new_cap(size_type add_size); + + // assign + + void fill_assign(size_type n, const value_type& value); - // copy_assign 函数 - template template - void vector::copy_assign(IIter first, IIter last, input_iterator_tag) { - auto cur = begin_; - for (; first != last && cur != end_; ++first, ++cur) { - *cur = *first; - } - if (first == last) { - erase(cur, end_); - } - else { - insert(end_, first, last); - } - } + void copy_assign(IIter first, IIter last, input_iterator_tag); - // 用 [first, last) 为容器赋值 - template template - void vector::copy_assign(FIter first, FIter last, forward_iterator_tag) { - const size_type len = mystl::distance(first, last); + void copy_assign(FIter first, FIter last, forward_iterator_tag); + + // reallocate + + template + void reallocate_emplace(iterator pos, Args&&... args); + void reallocate_insert(iterator pos, const value_type& value); + + // insert + + iterator fill_insert(iterator pos, size_type n, const value_type& value); + template + void copy_insert(iterator pos, IIter first, IIter last); + + // shrink_to_fit + + void reinsert(size_type size); +}; + +/*****************************************************************************************/ + +// 复制赋值操作符 +template +vector& vector::operator=(const vector& rhs) { + if (this != &rhs) { + const auto len = rhs.size(); if (len > capacity()) { - vector tmp(first, last); + vector tmp(rhs.begin(), rhs.end()); swap(tmp); } else if (size() >= len) { - auto new_end = mystl::copy(first, last, begin_); - data_allocator::destroy(new_end, end_); - end_ = new_end; + auto i = mystl::copy(rhs.begin(), rhs.end(), begin()); + data_allocator::destroy(i, end_); + end_ = begin_ + len; } else { - auto mid = first; - mystl::advance(mid, size()); - mystl::copy(first, mid, begin_); - auto new_end = mystl::uninitialized_copy(mid, last, end_); - end_ = new_end; + mystl::copy(rhs.begin(), rhs.begin() + size(), begin_); + mystl::uninitialized_copy(rhs.begin() + size(), rhs.end(), end_); + cap_ = end_ = begin_ + len; + } + } + return *this; +} + +// 移动赋值操作符 +template +vector& vector::operator=(vector&& rhs) noexcept { + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = rhs.begin_; + end_ = rhs.end_; + cap_ = rhs.cap_; + rhs.begin_ = nullptr; + rhs.end_ = nullptr; + rhs.cap_ = nullptr; + return *this; +} + +// 预留空间大小,当原容量小于要求大小时,才会重新分配 +template +void vector::reserve(size_type n) { + if (capacity() < n) { + THROW_LENGTH_ERROR_IF( + n > max_size(), + "n can not larger than max_size() in vector::reserve(n)"); + const auto old_size = size(); + auto tmp = data_allocator::allocate(n); + mystl::uninitialized_move(begin_, end_, tmp); + data_allocator::deallocate(begin_, cap_ - begin_); + begin_ = tmp; + end_ = tmp + old_size; + cap_ = begin_ + n; + } +} + +// 放弃多余的容量 +template +void vector::shrink_to_fit() { + if (end_ < cap_) { + reinsert(size()); + } +} + +// 在 pos 位置就地构造元素,避免额外的复制或移动开销 +template +template +typename vector::iterator +vector::emplace(const_iterator pos, Args&&... args) { + MYSTL_DEBUG(pos >= begin() && pos <= end()); + iterator xpos = const_cast(pos); + const size_type n = xpos - begin_; + if (end_ != cap_ && xpos == end_) { + data_allocator::construct(mystl::address_of(*end_), + mystl::forward(args)...); + ++end_; + } + else if (end_ != cap_) { + auto new_end = end_; + data_allocator::construct(mystl::address_of(*end_), *(end_ - 1)); + ++new_end; + mystl::copy_backward(xpos, end_ - 1, end_); + *xpos = value_type(mystl::forward(args)...); + } + else { + reallocate_emplace(xpos, mystl::forward(args)...); + } + return begin() + n; +} + +// 在尾部就地构造元素,避免额外的复制或移动开销 +template +template +void vector::emplace_back(Args&&... args) { + if (end_ < cap_) { + data_allocator::construct(mystl::address_of(*end_), + mystl::forward(args)...); + ++end_; + } + else { + reallocate_emplace(end_, mystl::forward(args)...); + } +} + +// 在尾部插入元素 +template +void vector::push_back(const value_type& value) { + if (end_ != cap_) { + data_allocator::construct(mystl::address_of(*end_), value); + ++end_; + } + else { + reallocate_insert(end_, value); + } +} + +// 弹出尾部元素 +template +void vector::pop_back() { + MYSTL_DEBUG(!empty()); + data_allocator::destroy(end_ - 1); + --end_; +} + +// 在 pos 处插入元素 +template +typename vector::iterator +vector::insert(const_iterator pos, const value_type& value) { + MYSTL_DEBUG(pos >= begin() && pos <= end()); + iterator xpos = const_cast(pos); + const size_type n = pos - begin_; + if (end_ != cap_ && xpos == end_) { + data_allocator::construct(mystl::address_of(*end_), value); + ++end_; + } + else if (end_ != cap_) { + auto new_end = end_; + data_allocator::construct(mystl::address_of(*end_), *(end_ - 1)); + ++new_end; + auto value_copy = value; // 避免元素因以下复制操作而被改变 + mystl::copy_backward(xpos, end_ - 1, end_); + *xpos = mystl::move(value_copy); + end_ = new_end; + } + else { + reallocate_insert(xpos, value); + } + return begin_ + n; +} + +// 删除 pos 位置上的元素 +template +typename vector::iterator vector::erase(const_iterator pos) { + MYSTL_DEBUG(pos >= begin() && pos < end()); + iterator xpos = begin_ + (pos - begin()); + mystl::move(xpos + 1, end_, xpos); + data_allocator::destroy(end_ - 1); + --end_; + return xpos; +} + +// 删除[first, last)上的元素 +template +typename vector::iterator +vector::erase(const_iterator first, const_iterator last) { + MYSTL_DEBUG(first >= begin() && last <= end() && !(last < first)); + const auto n = first - begin(); + iterator r = begin_ + (first - begin()); + data_allocator::destroy(mystl::move(r + (last - first), end_, r), end_); + end_ = end_ - (last - first); + return begin_ + n; +} + +// 重置容器大小 +template +void vector::resize(size_type new_size, const value_type& value) { + if (new_size < size()) { + erase(begin() + new_size, end()); + } + else { + insert(end(), new_size - size(), value); + } +} + +// 与另一个 vector 交换 +template +void vector::swap(vector& rhs) noexcept { + if (this != &rhs) { + mystl::swap(begin_, rhs.begin_); + mystl::swap(end_, rhs.end_); + mystl::swap(cap_, rhs.cap_); + } +} + +/*****************************************************************************************/ +// helper function + +// try_init 函数,若分配失败则忽略,不抛出异常 +template +void vector::try_init() noexcept { + try { + begin_ = data_allocator::allocate(16); + end_ = begin_; + cap_ = begin_ + 16; + } catch (...) { + begin_ = nullptr; + end_ = nullptr; + cap_ = nullptr; + } +} + +// init_space 函数 +template +void vector::init_space(size_type size, size_type cap) { + try { + begin_ = data_allocator::allocate(cap); + end_ = begin_ + size; + cap_ = begin_ + cap; + } catch (...) { + begin_ = nullptr; + end_ = nullptr; + cap_ = nullptr; + throw; + } +} + +// fill_init 函数 +template +void vector::fill_init(size_type n, const value_type& value) { + const size_type init_size = mystl::max(static_cast(16), n); + init_space(n, init_size); + mystl::uninitialized_fill_n(begin_, n, value); +} + +// range_init 函数 +template +template +void vector::range_init(Iter first, Iter last) { + const size_type init_size = mystl::max(static_cast(last - first), + static_cast(16)); + init_space(static_cast(last - first), init_size); + mystl::uninitialized_copy(first, last, begin_); +} + +// destroy_and_recover 函数 +template +void vector::destroy_and_recover(iterator first, iterator last, + size_type n) { + data_allocator::destroy(first, last); + data_allocator::deallocate(first, n); +} + +// get_new_cap 函数 +template +typename vector::size_type vector::get_new_cap(size_type add_size) { + const auto old_size = capacity(); + THROW_LENGTH_ERROR_IF(old_size > max_size() - add_size, + "vector's size too big"); + if (old_size > max_size() - old_size / 2) { + return old_size + add_size > max_size() - 16 ? old_size + add_size + : old_size + add_size + 16; + } + const size_type new_size + = old_size == 0 + ? mystl::max(add_size, static_cast(16)) + : mystl::max(old_size + old_size / 2, old_size + add_size); + return new_size; +} + +// fill_assign 函数 +template +void vector::fill_assign(size_type n, const value_type& value) { + if (n > capacity()) { + vector tmp(n, value); + swap(tmp); + } + else if (n > size()) { + mystl::fill(begin(), end(), value); + end_ = mystl::uninitialized_fill_n(end_, n - size(), value); + } + else { + erase(mystl::fill_n(begin_, n, value), end_); + } +} + +// copy_assign 函数 +template +template +void vector::copy_assign(IIter first, IIter last, input_iterator_tag) { + auto cur = begin_; + for (; first != last && cur != end_; ++first, ++cur) { + *cur = *first; + } + if (first == last) { + erase(cur, end_); + } + else { + insert(end_, first, last); + } +} + +// 用 [first, last) 为容器赋值 +template +template +void vector::copy_assign(FIter first, FIter last, forward_iterator_tag) { + const size_type len = mystl::distance(first, last); + if (len > capacity()) { + vector tmp(first, last); + swap(tmp); + } + else if (size() >= len) { + auto new_end = mystl::copy(first, last, begin_); + data_allocator::destroy(new_end, end_); + end_ = new_end; + } + else { + auto mid = first; + mystl::advance(mid, size()); + mystl::copy(first, mid, begin_); + auto new_end = mystl::uninitialized_copy(mid, last, end_); + end_ = new_end; + } +} + +// 重新分配空间并在 pos 处就地构造元素 +template +template +void vector::reallocate_emplace(iterator pos, Args&&... args) { + const auto new_size = get_new_cap(1); + auto new_begin = data_allocator::allocate(new_size); + auto new_end = new_begin; + try { + new_end = mystl::uninitialized_move(begin_, pos, new_begin); + data_allocator::construct(mystl::address_of(*new_end), + mystl::forward(args)...); + ++new_end; + new_end = mystl::uninitialized_move(pos, end_, new_end); + } catch (...) { + data_allocator::deallocate(new_begin, new_size); + throw; + } + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = new_begin; + end_ = new_end; + cap_ = new_begin + new_size; +} + +// 重新分配空间并在 pos 处插入元素 +template +void vector::reallocate_insert(iterator pos, const value_type& value) { + const auto new_size = get_new_cap(1); + auto new_begin = data_allocator::allocate(new_size); + auto new_end = new_begin; + const value_type& value_copy = value; + try { + new_end = mystl::uninitialized_move(begin_, pos, new_begin); + data_allocator::construct(mystl::address_of(*new_end), value_copy); + ++new_end; + new_end = mystl::uninitialized_move(pos, end_, new_end); + } catch (...) { + data_allocator::deallocate(new_begin, new_size); + throw; + } + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = new_begin; + end_ = new_end; + cap_ = new_begin + new_size; +} + +// fill_insert 函数 +template +typename vector::iterator +vector::fill_insert(iterator pos, size_type n, const value_type& value) { + if (n == 0) { + return pos; + } + const size_type xpos = pos - begin_; + const value_type value_copy = value; // 避免被覆盖 + if (static_cast(cap_ - end_) + >= n) { // 如果备用空间大于等于增加的空间 + const size_type after_elems = end_ - pos; + auto old_end = end_; + if (after_elems > n) { + mystl::uninitialized_copy(end_ - n, end_, end_); + end_ += n; + mystl::move_backward(pos, old_end - n, old_end); + mystl::uninitialized_fill_n(pos, n, value_copy); + } + else { + end_ + = mystl::uninitialized_fill_n(end_, n - after_elems, value_copy); + end_ = mystl::uninitialized_move(pos, old_end, end_); + mystl::uninitialized_fill_n(pos, after_elems, value_copy); } } - - // 重新分配空间并在 pos 处就地构造元素 - template - template - void vector::reallocate_emplace(iterator pos, Args &&...args) { - const auto new_size = get_new_cap(1); + else { // 如果备用空间不足 + const auto new_size = get_new_cap(n); auto new_begin = data_allocator::allocate(new_size); auto new_end = new_begin; try { new_end = mystl::uninitialized_move(begin_, pos, new_begin); - data_allocator::construct(mystl::address_of(*new_end), - mystl::forward(args)...); - ++new_end; + new_end = mystl::uninitialized_fill_n(new_end, n, value); new_end = mystl::uninitialized_move(pos, end_, new_end); } catch (...) { - data_allocator::deallocate(new_begin, new_size); + destroy_and_recover(new_begin, new_end, new_size); throw; } - destroy_and_recover(begin_, end_, cap_ - begin_); - begin_ = new_begin; - end_ = new_end; - cap_ = new_begin + new_size; - } - - // 重新分配空间并在 pos 处插入元素 - template - void vector::reallocate_insert(iterator pos, const value_type &value) { - const auto new_size = get_new_cap(1); - auto new_begin = data_allocator::allocate(new_size); - auto new_end = new_begin; - const value_type &value_copy = value; - try { - new_end = mystl::uninitialized_move(begin_, pos, new_begin); - data_allocator::construct(mystl::address_of(*new_end), value_copy); - ++new_end; - new_end = mystl::uninitialized_move(pos, end_, new_end); - } catch (...) { - data_allocator::deallocate(new_begin, new_size); - throw; - } - destroy_and_recover(begin_, end_, cap_ - begin_); + data_allocator::deallocate(begin_, cap_ - begin_); begin_ = new_begin; end_ = new_end; - cap_ = new_begin + new_size; - } - - // fill_insert 函数 - template - typename vector::iterator - vector::fill_insert(iterator pos, size_type n, const value_type &value) { - if (n == 0) - return pos; - const size_type xpos = pos - begin_; - const value_type value_copy = value; // 避免被覆盖 - if (static_cast(cap_ - end_) >= - n) { // 如果备用空间大于等于增加的空间 - const size_type after_elems = end_ - pos; - auto old_end = end_; - if (after_elems > n) { - mystl::uninitialized_copy(end_ - n, end_, end_); - end_ += n; - mystl::move_backward(pos, old_end - n, old_end); - mystl::uninitialized_fill_n(pos, n, value_copy); - } - else { - end_ = mystl::uninitialized_fill_n(end_, n - after_elems, - value_copy); - end_ = mystl::uninitialized_move(pos, old_end, end_); - mystl::uninitialized_fill_n(pos, after_elems, value_copy); - } - } - else { // 如果备用空间不足 - const auto new_size = get_new_cap(n); - auto new_begin = data_allocator::allocate(new_size); - auto new_end = new_begin; - try { - new_end = mystl::uninitialized_move(begin_, pos, new_begin); - new_end = mystl::uninitialized_fill_n(new_end, n, value); - new_end = mystl::uninitialized_move(pos, end_, new_end); - } catch (...) { - destroy_and_recover(new_begin, new_end, new_size); - throw; - } - data_allocator::deallocate(begin_, cap_ - begin_); - begin_ = new_begin; - end_ = new_end; - cap_ = begin_ + new_size; - } - return begin_ + xpos; - } - - // copy_insert 函数 - template - template - void vector::copy_insert(iterator pos, IIter first, IIter last) { - if (first == last) - return; - const auto n = mystl::distance(first, last); - if ((cap_ - end_) >= n) { // 如果备用空间大小足够 - const auto after_elems = end_ - pos; - auto old_end = end_; - if (after_elems > n) { - end_ = mystl::uninitialized_copy(end_ - n, end_, end_); - mystl::move_backward(pos, old_end - n, old_end); - mystl::uninitialized_copy(first, last, pos); - } - else { - auto mid = first; - mystl::advance(mid, after_elems); - end_ = mystl::uninitialized_copy(mid, last, end_); - end_ = mystl::uninitialized_move(pos, old_end, end_); - mystl::uninitialized_copy(first, mid, pos); - } + cap_ = begin_ + new_size; + } + return begin_ + xpos; +} + +// copy_insert 函数 +template +template +void vector::copy_insert(iterator pos, IIter first, IIter last) { + if (first == last) { + return; + } + const auto n = mystl::distance(first, last); + if ((cap_ - end_) >= n) { // 如果备用空间大小足够 + const auto after_elems = end_ - pos; + auto old_end = end_; + if (after_elems > n) { + end_ = mystl::uninitialized_copy(end_ - n, end_, end_); + mystl::move_backward(pos, old_end - n, old_end); + mystl::uninitialized_copy(first, last, pos); } - else { // 备用空间不足 - const auto new_size = get_new_cap(n); - auto new_begin = data_allocator::allocate(new_size); - auto new_end = new_begin; - try { - new_end = mystl::uninitialized_move(begin_, pos, new_begin); - new_end = mystl::uninitialized_copy(first, last, new_end); - new_end = mystl::uninitialized_move(pos, end_, new_end); - } catch (...) { - destroy_and_recover(new_begin, new_end, new_size); - throw; - } - data_allocator::deallocate(begin_, cap_ - begin_); - begin_ = new_begin; - end_ = new_end; - cap_ = begin_ + new_size; + else { + auto mid = first; + mystl::advance(mid, after_elems); + end_ = mystl::uninitialized_copy(mid, last, end_); + end_ = mystl::uninitialized_move(pos, old_end, end_); + mystl::uninitialized_copy(first, mid, pos); } } - - // reinsert 函数 - template - void vector::reinsert(size_type size) { - auto new_begin = data_allocator::allocate(size); + else { // 备用空间不足 + const auto new_size = get_new_cap(n); + auto new_begin = data_allocator::allocate(new_size); + auto new_end = new_begin; try { - mystl::uninitialized_move(begin_, end_, new_begin); + new_end = mystl::uninitialized_move(begin_, pos, new_begin); + new_end = mystl::uninitialized_copy(first, last, new_end); + new_end = mystl::uninitialized_move(pos, end_, new_end); } catch (...) { - data_allocator::deallocate(new_begin, size); + destroy_and_recover(new_begin, new_end, new_size); throw; } data_allocator::deallocate(begin_, cap_ - begin_); begin_ = new_begin; - end_ = begin_ + size; - cap_ = begin_ + size; - } - - /*****************************************************************************************/ - // 重载比较操作符 - - template - bool operator==(const vector &lhs, const vector &rhs) { - return lhs.size() == rhs.size() && - mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - - template - bool operator<(const vector &lhs, const vector &rhs) { - return mystl::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), lhs.end()); - } - - template - bool operator!=(const vector &lhs, const vector &rhs) { - return !(lhs == rhs); - } - - template - bool operator>(const vector &lhs, const vector &rhs) { - return rhs < lhs; - } - - template - bool operator<=(const vector &lhs, const vector &rhs) { - return !(rhs < lhs); - } - - template - bool operator>=(const vector &lhs, const vector &rhs) { - return !(lhs < rhs); - } - - // 重载 mystl 的 swap - template - void swap(vector &lhs, vector &rhs) { - lhs.swap(rhs); - } - -}; - -#endif /* _VECTOR_ */ + end_ = new_end; + cap_ = begin_ + new_size; + } +} + +// reinsert 函数 +template +void vector::reinsert(size_type size) { + auto new_begin = data_allocator::allocate(size); + try { + mystl::uninitialized_move(begin_, end_, new_begin); + } catch (...) { + data_allocator::deallocate(new_begin, size); + throw; + } + data_allocator::deallocate(begin_, cap_ - begin_); + begin_ = new_begin; + end_ = begin_ + size; + cap_ = begin_ + size; +} + +/*****************************************************************************************/ +// 重载比较操作符 + +template +bool operator==(const vector& lhs, const vector& rhs) { + return lhs.size() == rhs.size() + && mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator<(const vector& lhs, const vector& rhs) { + return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), + lhs.end()); +} + +template +bool operator!=(const vector& lhs, const vector& rhs) { + return !(lhs == rhs); +} + +template +bool operator>(const vector& lhs, const vector& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const vector& lhs, const vector& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const vector& lhs, const vector& rhs) { + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(vector& lhs, vector& rhs) { + lhs.swap(rhs); +} + +}; // namespace mystl + +#endif /* SIMPLEKERNEL_VECTOR */ diff --git a/src/libcxx/src/__dso_handle.S b/src/libcxx/src/__dso_handle.S index 0363ffb06..88a752e8e 100644 --- a/src/libcxx/src/__dso_handle.S +++ b/src/libcxx/src/__dso_handle.S @@ -13,6 +13,6 @@ #ifndef CRT_LEGACY_WORKAROUND .hidden __dso_handle #endif -.globl __dso_handle +.global __dso_handle __dso_handle: .long 0 diff --git a/src/libcxx/src/cxxabi.cpp b/src/libcxx/src/cxxabi.cpp index 47d63a519..088cda876 100644 --- a/src/libcxx/src/cxxabi.cpp +++ b/src/libcxx/src/cxxabi.cpp @@ -1,21 +1,32 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://wiki.osdev.org/C%2B%2B -// cxxabi.cpp for Simple-XX/SimpleKernel. - -#include "cxxabi.h" -#include "new" +/** + * @file cxxabi.cpp + * @brief C++ abi 支持 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://wiki.osdev.org/C%2B%2B + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ #ifdef __cplusplus extern "C" { #endif +#include "cxxabi.h" + #define ATEXIT_MAX_FUNCS 128 typedef void (*ctor_t)(void); -extern ctor_t ctors_start[]; -extern ctor_t ctors_end[]; +// 在 link.ld 中定义 +extern ctor_t __init_array_start[]; +extern ctor_t __init_array_end[]; typedef unsigned uarch_t; @@ -25,14 +36,14 @@ struct atexit_func_entry_t { 12bytes. * 128 * 12 = 1.5KB exact. **/ - void (*destructor_func)(void *); - void *obj_ptr; - void *dso_handle; + void (*destructor_func)(void*); + void* obj_ptr; + void* dso_handle; }; void cpp_init(void) { - ctor_t *f; - for (f = ctors_start; f < ctors_end; f++) { + ctor_t* f; + for (f = __init_array_start; f < __init_array_end; f++) { (*f)(); } return; @@ -45,9 +56,9 @@ void __cxa_pure_virtual(void) { atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS]; uarch_t __atexit_func_count = 0; -extern void *__dso_handle; +extern void* __dso_handle; -void __cxa_rethrow() { +void __cxa_rethrow() { return; } @@ -67,7 +78,7 @@ void __gxx_personality_v0() { return; } -int __cxa_atexit(void (*f)(void *), void *objptr, void *dso) { +int __cxa_atexit(void (*f)(void*), void* objptr, void* dso) { if (__atexit_func_count >= ATEXIT_MAX_FUNCS) { return -1; }; @@ -78,7 +89,7 @@ int __cxa_atexit(void (*f)(void *), void *objptr, void *dso) { return 0; }; -int __aeabi_atexit(void (*f)(void *), void *objptr, void *dso) { +int __aeabi_atexit(void (*f)(void*), void* objptr, void* dso) { if (__atexit_func_count >= ATEXIT_MAX_FUNCS) { return -1; }; @@ -89,7 +100,7 @@ int __aeabi_atexit(void (*f)(void *), void *objptr, void *dso) { return 0; }; -void __cxa_finalize(void *f) { +void __cxa_finalize(void* f) { uarch_t i = __atexit_func_count; if (!f) { /* @@ -106,7 +117,7 @@ void __cxa_finalize(void *f) { *be used to tell when a shared object is no longer in use. It is *one of many methods, however. **/ - // You may insert a prinf() here to tell you whether or not the + // You may insert a printf() here to tell you whether or not the // function gets called. Testing is CRITICAL! while (i--) { if (__atexit_funcs[i].destructor_func) { @@ -176,39 +187,37 @@ void __cxa_finalize(void *f) { }; namespace __cxxabiv1 { - /* guard variables */ /* The ABI requires a 64-bit type. */ __extension__ typedef int __guard __attribute__((mode(__DI__))); -int __cxa_guard_acquire(__guard *); -void __cxa_guard_release(__guard *); -void __cxa_guard_abort(__guard *); +int __cxa_guard_acquire(__guard*); +void __cxa_guard_release(__guard*); +void __cxa_guard_abort(__guard*); -int __cxa_guard_acquire(__guard *g) { - return !*(char *)(g); +int __cxa_guard_acquire(__guard* g) { + return !*(char*)(g); } -void __cxa_guard_release(__guard *g) { - *(char *)g = 1; +void __cxa_guard_release(__guard* g) { + *(char*)g = 1; } -void __cxa_guard_abort(__guard *) { - return; +void __cxa_guard_abort(__guard*) { } -} // namespace __cxxabiv1 +} // namespace __cxxabiv1 #ifdef __cplusplus }; #endif namespace std { -type_info::type_info(const type_info &arg) : tname(arg.tname) { +type_info::type_info(const type_info& arg) : tname(arg.tname) { return; } -type_info::type_info(const char *pname) : tname(pname) { +type_info::type_info(const char* pname) : tname(pname) { return; } @@ -216,27 +225,27 @@ type_info::~type_info(void) { return; } -const char *type_info::name(void) const { +const char* type_info::name(void) const { return tname; } -bool type_info::operator==(const type_info &arg) const { +bool type_info::operator==(const type_info& arg) const { return tname == arg.tname; } -bool type_info::operator!=(const type_info &arg) const { +bool type_info::operator!=(const type_info& arg) const { return tname != arg.tname; } -} // namespace std +} // namespace std namespace __cxxabiv1 { -#define ADD_CXX_TYPEINFO_SOURCE(t) \ - t::t(const char *n) : std::type_info(n) { \ - return; \ - } \ - t::~t(void) { \ - return; \ +#define ADD_CXX_TYPEINFO_SOURCE(t) \ + t::t(const char* n) : std::type_info(n) { \ + return; \ + } \ + t::~t(void) { \ + return; \ } ADD_CXX_TYPEINFO_SOURCE(__fundamental_type_info) @@ -252,4 +261,4 @@ ADD_CXX_TYPEINFO_SOURCE(__vmi_class_type_info) #undef ADD_CXX_TYPEINFO_SOURCE -} // namespace __cxxabiv1 +} // namespace __cxxabiv1 diff --git a/src/libcxx/src/iostream.cpp b/src/libcxx/src/iostream.cpp index e654c2c58..bdd8a3c9d 100755 --- a/src/libcxx/src/iostream.cpp +++ b/src/libcxx/src/iostream.cpp @@ -1,54 +1,48 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// Based on https://github.com/MRNIU/MiniCRT -// iostream.cpp for Simple-XX/SimpleKernel. - -#include "stddef.h" -#include "string.h" -#include "stdio.h" +/** + * @file iostream + * @brief C++ 输入输出 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/MRNIU/MiniCRT + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + #include "iostream" +#include "cstdio" namespace std { - ostream::ostream(void) { - return; - } - - ostream::~ostream(void) { - return; - } - - ostream &ostream::operator<<(char c) { - printf("%c", c); - return *this; - } - - ostream &ostream::operator<<(int n) { - printf("%d", n); - return *this; - } - - ostream &ostream::operator<<(unsigned int n) { - printf("%u", n); - return *this; - } - - ostream &ostream::operator<<(long n) { - printf("%d", n); - return *this; - } - - ostream &ostream::operator<<(unsigned long n) { - printf("%u", n); - return *this; - } - - ostream &ostream::operator<<(const char *lhs) { - printf("%s", lhs); - return *this; - } - - ostream &ostream::operator<<(ostream &(*manip)(ostream &)) { - return manip(*this); - } -}; +ostream::ostream(void) { + return; +} + +ostream::~ostream(void) { + return; +} + +ostream& ostream::operator<<(char c) { + printf("%c", c); + return *this; +} + +ostream& ostream::operator<<(int n) { + printf("%d", n); + return *this; +} + +ostream& ostream::operator<<(const char* lhs) { + printf("%s", lhs); + return *this; +} + +ostream& ostream::operator<<(ostream& (*manip)(ostream&)) { + return manip(*this); +} +}; // namespace std diff --git a/src/libcxx/src/new.cpp b/src/libcxx/src/new.cpp index d2dd633ec..eed7a9ee7 100644 --- a/src/libcxx/src/new.cpp +++ b/src/libcxx/src/new.cpp @@ -1,76 +1,87 @@ -// This file is a part of Simple-XX/SimpleKernel -// (https://github.com/Simple-XX/SimpleKernel). -// -// new.cpp for Simple-XX/SimpleKernel. +/** + * @file new.cpp + * @brief 内存分配实现 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ #include "new" -#include "stdlib.h" +#include "cstdlib" -void *operator new(size_t _size) { - return malloc(_size); +void* operator new(size_t _size) { + return kmalloc(_size); } -void *operator new[](size_t _size) { - return malloc(_size); +void* operator new[](size_t _size) { + return kmalloc(_size); } -void operator delete(void *_p) { - free(_p); +void operator delete(void* _p) { + kfree(_p); } -void operator delete(void *_p, size_t) { - free(_p); +void operator delete(void* _p, size_t) { + kfree(_p); } -void operator delete[](void *_p) { - free(_p); +void operator delete[](void* _p) { + kfree(_p); } -void operator delete[](void *_p, size_t) { - free(_p); +void operator delete[](void* _p, size_t) { + kfree(_p); } -void *operator new(size_t, void *_p) throw() { +void* operator new(size_t, void* _p) throw() { return _p; } -void *operator new[](size_t, void *_p) throw() { +void* operator new[](size_t, void* _p) throw() { return _p; } -void operator delete(void *, void *) throw() { +void operator delete(void*, void*) throw() { return; } -void operator delete[](void *, void *) throw() { +void operator delete[](void*, void*) throw() { return; } // TODO -void *operator new(size_t _size, std::align_val_t) { - return malloc(_size); +void* operator new(size_t _size, std::align_val_t) { + return kmalloc(_size); } -void operator delete(void *_p, std::align_val_t) { - free(_p); +void operator delete(void* _p, std::align_val_t) { + kfree(_p); return; } -void *operator new[](size_t _size, std::align_val_t) { - return malloc(_size); +void* operator new[](size_t _size, std::align_val_t) { + return kmalloc(_size); } -void operator delete[](void *_p, std::align_val_t) { - free(_p); +void operator delete[](void* _p, std::align_val_t) { + kfree(_p); return; } -void operator delete(void *_p, size_t, std::align_val_t) { - free(_p); +void operator delete(void* _p, size_t, std::align_val_t) { + kfree(_p); return; } -void operator delete[](void *_p, size_t, std::align_val_t) { - free(_p); + +void operator delete[](void* _p, size_t, std::align_val_t) { + kfree(_p); return; } diff --git a/src/libcxx/src/stack_chk.cpp b/src/libcxx/src/stack_chk.cpp new file mode 100644 index 000000000..e0ac0623d --- /dev/null +++ b/src/libcxx/src/stack_chk.cpp @@ -0,0 +1,32 @@ + +/** + * @file stack_chk.cpp + * @brief 栈保护 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-05-08 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * Based on https://github.com/MRNIU/MiniCRT + * @par change log: + * + *
DateAuthorDescription + *
2023-05-08Zone.N创建文件 + *
+ */ + +#include "cstdint" +#include "cstdio" + +#if UINT32_MAX == UINTPTR_MAX +# define STACK_CHK_GUARD 0xe2dee396 +#else +# define STACK_CHK_GUARD 0x595e9fbd94fda766 +#endif + +uintptr_t __stack_chk_guard = STACK_CHK_GUARD; + +void __stack_chk_fail(void) { + err("Stack smashing detected\n"); + return; +} diff --git a/tools/.Clion_usage.assets/2022-01-16 22.41.38.png b/tools/.Clion_usage.assets/2022-01-16 22.41.38.png new file mode 100644 index 000000000..f83a47fd2 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.41.38.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.42.21.png b/tools/.Clion_usage.assets/2022-01-16 22.42.21.png new file mode 100644 index 000000000..ef47d0703 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.42.21.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.42.56.png b/tools/.Clion_usage.assets/2022-01-16 22.42.56.png new file mode 100644 index 000000000..0ecf20bb7 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.42.56.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.44.30.png b/tools/.Clion_usage.assets/2022-01-16 22.44.30.png new file mode 100644 index 000000000..41b75fd61 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.44.30.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.45.14.png b/tools/.Clion_usage.assets/2022-01-16 22.45.14.png new file mode 100644 index 000000000..e33558f96 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.45.14.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.48.24.png b/tools/.Clion_usage.assets/2022-01-16 22.48.24.png new file mode 100644 index 000000000..f3b6d2478 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.48.24.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.52.00.png b/tools/.Clion_usage.assets/2022-01-16 22.52.00.png new file mode 100644 index 000000000..34031a37b Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.52.00.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.54.02.png b/tools/.Clion_usage.assets/2022-01-16 22.54.02.png new file mode 100644 index 000000000..e52a45b1f Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.54.02.png differ diff --git a/tools/.Clion_usage.assets/2022-01-16 22.56.43.png b/tools/.Clion_usage.assets/2022-01-16 22.56.43.png new file mode 100644 index 000000000..4a0e3186c Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-16 22.56.43.png differ diff --git a/tools/.Clion_usage.assets/2022-01-17 16.29.12.png b/tools/.Clion_usage.assets/2022-01-17 16.29.12.png new file mode 100644 index 000000000..72a0efd0d Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-17 16.29.12.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.49.01.png b/tools/.Clion_usage.assets/2022-01-22 19.49.01.png new file mode 100644 index 000000000..833d4503e Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.49.01.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.49.07.png b/tools/.Clion_usage.assets/2022-01-22 19.49.07.png new file mode 100644 index 000000000..93fd8d4e6 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.49.07.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.53.12.png b/tools/.Clion_usage.assets/2022-01-22 19.53.12.png new file mode 100644 index 000000000..78bdc053e Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.53.12.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.53.34-2852427.png b/tools/.Clion_usage.assets/2022-01-22 19.53.34-2852427.png new file mode 100644 index 000000000..e10b13a07 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.53.34-2852427.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.53.34.png b/tools/.Clion_usage.assets/2022-01-22 19.53.34.png new file mode 100644 index 000000000..e10b13a07 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.53.34.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.54.15.png b/tools/.Clion_usage.assets/2022-01-22 19.54.15.png new file mode 100644 index 000000000..f2ac78474 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.54.15.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.55.16.png b/tools/.Clion_usage.assets/2022-01-22 19.55.16.png new file mode 100644 index 000000000..62405faa5 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.55.16.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.56.23.png b/tools/.Clion_usage.assets/2022-01-22 19.56.23.png new file mode 100644 index 000000000..41ce15989 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.56.23.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.56.31.png b/tools/.Clion_usage.assets/2022-01-22 19.56.31.png new file mode 100644 index 000000000..5313e0f21 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.56.31.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.57.31.png b/tools/.Clion_usage.assets/2022-01-22 19.57.31.png new file mode 100644 index 000000000..73ae65416 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.57.31.png differ diff --git a/tools/.Clion_usage.assets/2022-01-22 19.58.14.png b/tools/.Clion_usage.assets/2022-01-22 19.58.14.png new file mode 100644 index 000000000..02bd5f769 Binary files /dev/null and b/tools/.Clion_usage.assets/2022-01-22 19.58.14.png differ diff --git "a/tools/Clion \344\275\277\347\224\250\350\257\264\346\230\216.md" "b/tools/Clion \344\275\277\347\224\250\350\257\264\346\230\216.md" new file mode 100644 index 000000000..b01dc729d --- /dev/null +++ "b/tools/Clion \344\275\277\347\224\250\350\257\264\346\230\216.md" @@ -0,0 +1,110 @@ + +# CLion 配置及使用 + +## 配置 + +导入配置 + +![2022-01-17 16.29.12](.Clion_usage.assets/2022-01-17%2016.29.12.png) + +![2022-01-22 19.49.01](.Clion_usage.assets/2022-01-22%2019.49.01.png) + +![2022-01-22 19.49.07](.Clion_usage.assets/2022-01-22%2019.49.07.png) + +## 使用 + +osx+QEMU+RISCV64 + +1. 生成 CMake + + ![2022-01-16 22.41.38](.Clion_usage.assets/2022-01-16%2022.41.38.png) + + 执行后会在根目录生成三个文件夹,用于存放生成的文件 + + ![2022-01-16 22.42.21](.Clion_usage.assets/2022-01-16%2022.42.21.png) + + CLion 输出 + + ![2022-01-16 22.42.56](.Clion_usage.assets/2022-01-16%2022.42.56.png) + +2. 构建 kernel.elf + + ![2022-01-22 19.53.12](.Clion_usage.assets/2022-01-22%2019.53.12.png) + +3. 选择你需要构建的版本 + + ![2022-01-22 19.53.34](.Clion_usage.assets/2022-01-22%2019.53.34-2852427.png) + +4. 构建 + + ![2022-01-22 19.54.15](.Clion_usage.assets/2022-01-22%2019.54.15.png) + + 正常输出为 + + ![2022-01-16 22.44.30](.Clion_usage.assets/2022-01-16%2022.44.30.png) + + 同时会在 build_riscv64/bin 文件夹内生成文件 + + ![2022-01-16 22.45.14](.Clion_usage.assets/2022-01-16%2022.45.14.png) + + +5. 运行 + + ![2022-01-22 19.55.16](.Clion_usage.assets/2022-01-22%2019.55.16.png) + + + 虚拟机串口输出 + + ![2022-01-16 22.48.24](.Clion_usage.assets/2022-01-16%2022.48.24.png) + +--- + +osx+Bochs+i386 + +1. 生成 CMake + + ![2022-01-16 22.41.38](.Clion_usage.assets/2022-01-16%2022.41.38.png) + + 执行后会在根目录生成三个文件夹,用于存放生成的文件 + + ![2022-01-16 22.42.21](.Clion_usage.assets/2022-01-16%2022.42.21.png) + + CLion 输出 + + ![2022-01-16 22.52.00](.Clion_usage.assets/2022-01-16%2022.52.00.png) + + + +2. 构建 kernel.elf + + ![2022-01-22 19.56.23](.Clion_usage.assets/2022-01-22%2019.56.23.png) + + + + +3. 选择你需要构建的版本 + + ![2022-01-22 19.56.31](.Clion_usage.assets/2022-01-22%2019.56.31.png) + + + +4. 构建 + + ![2022-01-22 19.57.31](.Clion_usage.assets/2022-01-22%2019.57.31.png) + + 正常输出为 + + ![2022-01-16 22.54.02](.Clion_usage.assets/2022-01-16%2022.54.02.png) + + 同时会在 build_i386/bin 文件夹内生成文件 + + ![2022-01-16 22.45.14](.Clion_usage.assets/2022-01-16%2022.45.14.png) + + +5. 运行 + + ![2022-01-22 19.58.14](.Clion_usage.assets/2022-01-22%2019.58.14.png) + + 输出 + + ![2022-01-16 22.56.43](.Clion_usage.assets/2022-01-16%2022.56.43.png) \ No newline at end of file diff --git "a/tools/Cloin \347\216\257\345\242\203\346\220\255\345\273\272.md" "b/tools/Cloin \347\216\257\345\242\203\346\220\255\345\273\272.md" deleted file mode 100644 index e30069139..000000000 --- "a/tools/Cloin \347\216\257\345\242\203\346\220\255\345\273\272.md" +++ /dev/null @@ -1,42 +0,0 @@ -# Clion 环境搭建 - -NOTE: 未完成 - -以 riscv64 为例 - -## 工具链 - -![截屏2021-06-29 下午2.36.16](https://tva1.sinaimg.cn/large/008i3skNly1grz4mhjvazj31ka0u0alh.jpg) - -1. C Compiler: 修改为实际工具路径 -2. C++ Compiler: 修改为实际工具路径 -3. Debugger: 修改为实际工具路径 - -## CMake - -使用 Clion 打开该工程,如下配置 Clion 中的 cmake,配置参数: - -![截屏2021-06-29 下午2.53.54](/Users/nzh/Library/Application%20Support/typora-user-images/%E6%88%AA%E5%B1%8F2021-06-29%20%E4%B8%8B%E5%8D%882.53.54.png) - -1. `DCMAKE_TOOLCHAIN_FILE` 修改为实际需要的工具链, -2. `DARCH` 修改为要运行的架构 - -## 运行 - -需要借助 external tool 运行虚拟机 - -![截屏2021-06-29 下午3.07.00](https://tva1.sinaimg.cn/large/008i3skNly1grz5ig6ltuj31op0u0qp4.jpg) - -Working directory: 修改为实际 SimpleKernel 路径 - -## 调试 - -在 external tool 设置页面 Arguments 追加 `-gdb tcp::2333` - -![截屏2021-06-29 下午3.12.08](https://tva1.sinaimg.cn/large/008i3skNly1grz5nr2mnfj31s50u0wyg.jpg) - - - -## 使用 - -先运行 kernel.elf,再开启 debug diff --git a/tools/bochs.sh b/tools/bochs.sh deleted file mode 100644 index 4e5fbd991..000000000 --- a/tools/bochs.sh +++ /dev/null @@ -1,52 +0,0 @@ - -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). -# -# bochs.sh for Simple-XX/SimpleKernel. - -#!/bin/bash - -if ! [ -x "$(command -v pkg-config)" ]; then - echo 'Error: pkg-config is not installed.' - exit 1 -elif ! [ -x "$(command -v sdl2)" ]; then - echo 'Error: sdl2 is not installed.' - exit 1 -elif ! [ -x "$(command -v wget)" ]; then - echo 'Error: wget is not installed.' - exit 1 -elif ! [ -x "$(command -v tar)" ]; then - echo 'Error: tar is not installed.' - exit 1 -else - wget https://downloads.sourceforge.net/project/bochs/bochs/2.6.9/bochs-2.6.9.tar.gz - tar zxvf bochs-2.6.9.tar.gz - cd bochs-2.6.9 - ./configure \ - --with-nogui \ - --enable-disasm \ - --disable-docbook \ - --enable-x86-64 \ - --enable-pci \ - --enable-all-optimizations \ - --enable-plugins \ - --enable-cdrom \ - --enable-a20-pin \ - --enable-fpu \ - --enable-alignment-check \ - --enable-large-ramfile \ - --enable-debugger-gui \ - --enable-readline \ - --enable-iodebug \ - --enable-show-ips \ - --enable-logging \ - --enable-usb \ - --enable-cpu-level=6 \ - --enable-clgd54xx \ - --enable-avx \ - --enable-vmx=2 \ - --enable-long-phy-address \ - --with-term \ - --with-sdl2 - make - make install -fi diff --git a/tools/bochsinit b/tools/bochsinit deleted file mode 100644 index f2ad6c76f..000000000 --- a/tools/bochsinit +++ /dev/null @@ -1 +0,0 @@ -c diff --git a/tools/bochsrc_linux.txt b/tools/bochsrc_linux.txt deleted file mode 100644 index 3d1fa0e9e..000000000 --- a/tools/bochsrc_linux.txt +++ /dev/null @@ -1,31 +0,0 @@ - -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). -# -# bochsrc_linux.txt for Simple-XX/SimpleKernel - -ata1-master: type=cdrom, path="simplekernel.iso", status=inserted -boot: cdrom - -# log: ./debug_info/bochsout.txt - -megs: 128 -# Memory Detection in Emulators -# When you tell an emulator how much memory you want emulated, the concept is a little -# "fuzzy" because of the emulated missing bits of RAM below 1M. If you tell an emulator to -# emulate 32M, does that mean your address space definitely goes from 0 to 32M -1, with -# missing bits? Not necessarily. The emulator might assume that you mean 32M of contiguous -# memory above 1M, so it might end at 33M -1. Or it might assume that you mean 32M of -# total usable RAM, going from 0 to 32M + 384K -1. So don't be surprised if you see a -# "detected memory size" that does not exactly match your expectations. - -# 这里需要根据实际路径进行修改 -# Here needs to change as your real path. -# linux -romimage: file=/usr/share/bochs/BIOS-bochs-latest -vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest -mouse: enabled=1 -keyboard: keymap=/usr/share/bochs/keymaps/x11-pc-us.map -display_library: x - -clock: sync=realtime, time0=local -cpu: model=corei7_haswell_4770 diff --git a/tools/bochsrc_mac.txt b/tools/bochsrc_mac.txt deleted file mode 100644 index 16f0e271b..000000000 --- a/tools/bochsrc_mac.txt +++ /dev/null @@ -1,31 +0,0 @@ - -# This file is a part of Simple-XX/SimpleKernel (https://github.com/Simple-XX/SimpleKernel). -# -# bochsrc_mac.txt for Simple-XX/SimpleKernel - -ata1-master: type=cdrom, path="simplekernel.iso", status=inserted -boot: cdrom - -# log: ./debug_info/bochsout.txt - -megs: 128 -# Memory Detection in Emulators -# When you tell an emulator how much memory you want emulated, the concept is a little -# "fuzzy" because of the emulated missing bits of RAM below 1M. If you tell an emulator to -# emulate 32M, does that mean your address space definitely goes from 0 to 32M -1, with -# missing bits? Not necessarily. The emulator might assume that you mean 32M of contiguous -# memory above 1M, so it might end at 33M -1. Or it might assume that you mean 32M of -# total usable RAM, going from 0 to 32M + 384K -1. So don't be surprised if you see a -# "detected memory size" that does not exactly match your expectations. - -# 这里需要根据实际路径进行修改 -# Here needs to change as your real path. -romimage: file=/usr/local/share/bochs/BIOS-bochs-latest -vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest -# mouse: enabled=1 -keyboard: keymap=/usr/local/share/bochs/keymaps/sdl2-pc-us.map -display_library: sdl2 - - -clock: sync=realtime, time0=local -cpu: model=corei7_haswell_4770 diff --git a/tools/env.sh b/tools/env.sh index e2d798e22..bc0bc33bd 100644 --- a/tools/env.sh +++ b/tools/env.sh @@ -1,22 +1,21 @@ +#!/bin/bash -# This file is a part of Simple-XX/SimpleKernel +# This file is a part of Simple-XX/SimpleKernel # (https://github.com/Simple-XX/SimpleKernel). # # setup.sh for Simple-XX/SimpleKernel. # 指定要运行的 ARCH,并设置相关数据 -#!/bin/bash -# ARCH: i386, x86_64, riscv64 +# 指定要编译的目标架构 ARCH: i386, x86_64, riscv64 # ARCH="i386" # ARCH="x86_64" ARCH="riscv64" -# Use qeme for i386/x86_64, bochs for default -IA32_USE_QEMU=0 +DEBUG=0 # 内核映像 -kernel='./build/bin/kernel.elf' +kernel='./build_'${ARCH}'/bin/kernel.elf' iso_boot_grub='./iso/boot/grub' iso_boot='./iso/boot/' iso='./simplekernel.iso' @@ -35,7 +34,6 @@ if [ "${OS}" == "Linux" ]; then fi OPENSBI="$(pwd)/tools/opensbi/build/platform/generic/firmware/fw_jump.elf" GRUB_PATH="$(dirname $(which grub-file))" - bochsrc="./tools/bochsrc_linux.txt" elif [ "${OS}" == "Darwin" ]; then if [ "${ARCH}" == "i386" ] || [ "${ARCH}" == "x86_64" ]; then TOOLS="toolchain_mac_x86_64.cmake" @@ -47,5 +45,4 @@ elif [ "${OS}" == "Darwin" ]; then fi OPENSBI="$(pwd)/tools/opensbi/build/platform/generic/firmware/fw_jump.elf" GRUB_PATH="$(pwd)/tools/grub-2.04/build/grub/bin" - bochsrc="./tools/bochsrc_mac.txt" fi diff --git a/tools/gdbinit b/tools/gdbinit new file mode 100644 index 000000000..f4c3a7510 --- /dev/null +++ b/tools/gdbinit @@ -0,0 +1,4028 @@ +# INSTALL INSTRUCTIONS: save as ~/.gdbinit +# +# DESCRIPTION: A user-friendly gdb configuration file, for x86/x86_64 and ARM platforms. +# +# REVISION : 9.0 (23/06/2019) +# +# CONTRIBUTORS: mammon_, elaine, pusillus, mong, zhang le, l0kit, +# truthix the cyberpunk, fG!, gln +# +# FEEDBACK: https://reverse.put.as - reverser@put.as +# GITHUB: https://github.com/gdbinit/Gdbinit +# +# NOTES: 'help user' in gdb will list the commands/descriptions in this file +# 'context on' now enables auto-display of context screen +# +# MAC OS X NOTES: If you are using this on Mac OS X, you must either attach gdb to a process +# or launch gdb without any options and then load the binary file you want to analyse with "exec-file" option +# If you load the binary from the command line, like $gdb binary-name, this will not work as it should +# For more information, read it here https://reverse.put.as/2008/11/28/apples-gdb-bug/ +# +# UPDATE: This bug can be fixed in gdb source. Refer to https://reverse.put.as/2009/08/10/fix-for-apples-gdb-bug-or-why-apple-forks-are-bad/ +# and https://reverse.put.as/2009/08/26/gdb-patches/ (if you want the fixed binary for i386) +# +# An updated version of the patch and binary is available at https://reverse.put.as/2011/02/21/update-to-gdb-patches-fix-a-new-bug/ +# +# iOS NOTES: iOS gdb from Cydia (and Apple's) suffer from the same OS X bug. +# If you are using this on Mac OS X or iOS, you must either attach gdb to a process +# or launch gdb without any options and then load the binary file you want to analyse with "exec-file" option +# If you load the binary from the command line, like $gdb binary-name, this will not work as it should +# For more information, read it here https://reverse.put.as/2008/11/28/apples-gdb-bug/ +# +# CHANGELOG: (older changes at the end of the file) +# +# Version 9.0 +# Fixes to make everything work with GNU/GDB 8.3+ +# +# TODO: +# + +# __________________gdb options_________________ + +# set to 1 to have ARM target debugging as default, use the "arm" command to switch inside gdb +set $ARM = 0 +# set to 0 if you have problems with the colorized prompt - reported by Plouj with Ubuntu gdb 7.2 +set $COLOREDPROMPT = 1 +# color the first line of the disassembly - default is green, if you want to change it search for +# SETCOLOR1STLINE and modify it :-) +set $SETCOLOR1STLINE = 0 +# set to 0 to remove disassembly display (useful for scripted commands mass dumping) +set $SHOWDISASM = 1 +# set to 0 to remove display of objectivec messages (default is 1) +set $SHOWOBJECTIVEC = 1 +# set to 0 to remove display of cpu registers (default is 1) +set $SHOWCPUREGISTERS = 1 +# set to 1 to enable display of stack (default is 0) +set $SHOWSTACK = 0 +# set to 1 to enable display of data window (default is 0) +set $SHOWDATAWIN = 0 +# set to 0 to disable colored display of changed registers +set $SHOWREGCHANGES = 1 +# set to 1 so skip command to execute the instruction at the new location +# by default it EIP/RIP will be modified and update the new context but not execute the instruction +set $SKIPEXECUTE = 0 +# if $SKIPEXECUTE is 1 configure the type of execution +# 1 = use stepo (do not get into calls), 0 = use stepi (step into calls) +set $SKIPSTEP = 1 +# show the ARM opcodes - change to 0 if you don't want such thing (in x/i command) +set $ARMOPCODES = 0 +# x86 disassembly flavor: 0 for Intel, 1 for AT&T +set $X86FLAVOR = 0 +# use colorized output or not +set $USECOLOR = 1 +# to use with remote KDP +set $KDP64BITS = -1 +set $64BITS = 0 + +# macOS version works better with this setting off +set startup-with-shell off + +set confirm off +set verbose off +set history filename ~/.gdb_history +set history save + +set output-radix 0x10 +set input-radix 0x10 + +# These make gdb never pause in its output +set height 0 +set width 0 + +set $SHOW_CONTEXT = 1 +set $SHOW_NEST_INSN = 0 + +set $CONTEXTSIZE_STACK = 6 +set $CONTEXTSIZE_DATA = 8 +set $CONTEXTSIZE_CODE = 8 + +# __________________end gdb options_________________ +# + +# __________________color functions_________________ +# +# color codes +set $BLACK = 0 +set $RED = 1 +set $GREEN = 2 +set $YELLOW = 3 +set $BLUE = 4 +set $MAGENTA = 5 +set $CYAN = 6 +set $WHITE = 7 + +# CHANGME: If you want to modify the "theme" change the colors here +# or just create a ~/.gdbinit.local and set these variables there +set $COLOR_REGNAME = $GREEN +set $COLOR_REGVAL = $BLACK +set $COLOR_REGVAL_MODIFIED = $RED +set $COLOR_SEPARATOR = $BLUE +set $COLOR_CPUFLAGS = $RED + +# this is ugly but there's no else if available :-( +define color + if $USECOLOR == 1 + # BLACK + if $arg0 == 0 + echo \033[30m + else + # RED + if $arg0 == 1 + echo \[\e[0;31m\] + else + # GREEN + if $arg0 == 2 + echo \033[32m + else + # YELLOW + if $arg0 == 3 + echo \033[33m + else + # BLUE + if $arg0 == 4 + echo \033[34m + else + # MAGENTA + if $arg0 == 5 + echo \033[35m + else + # CYAN + if $arg0 == 6 + echo \033[36m + else + # WHITE + if $arg0 == 7 + echo \033[37m + end + end + end + end + end + end + end + end + end +end + +define color_reset + if $USECOLOR == 1 + echo \033[0m + end +end + +define color_bold + if $USECOLOR == 1 + #echo \033[1m + echo \[\e[1m\] + end +end + +define color_underline + if $USECOLOR == 1 + echo \033[4m + end +end + +# this way anyone can have their custom prompt - argp's idea :-) +# can also be used to redefine anything else in particular the colors aka theming +# just remap the color variables defined above +source ~/.gdbinit.local + +# can't use the color functions because we are using the set command +if $COLOREDPROMPT == 1 + set extended-prompt \[\e[0;31m\]gdb$ \[\e[0m\] +end + +# Initialize these variables else comparisons will fail for coloring +# we must initialize all of them at once, 32 and 64 bits, and ARM. +set $oldrax = 0 +set $oldrbx = 0 +set $oldrcx = 0 +set $oldrdx = 0 +set $oldrsi = 0 +set $oldrdi = 0 +set $oldrbp = 0 +set $oldrsp = 0 +set $oldr8 = 0 +set $oldr9 = 0 +set $oldr10 = 0 +set $oldr11 = 0 +set $oldr12 = 0 +set $oldr13 = 0 +set $oldr14 = 0 +set $oldr15 = 0 +set $oldeax = 0 +set $oldebx = 0 +set $oldecx = 0 +set $oldedx = 0 +set $oldesi = 0 +set $oldedi = 0 +set $oldebp = 0 +set $oldesp = 0 +set $oldr0 = 0 +set $oldr1 = 0 +set $oldr2 = 0 +set $oldr3 = 0 +set $oldr4 = 0 +set $oldr5 = 0 +set $oldr6 = 0 +set $oldr7 = 0 +set $oldsp = 0 +set $oldlr = 0 + +# used by ptraceme/rptraceme +set $ptrace_bpnum = 0 + +# ______________window size control___________ +define contextsize-stack + if $argc != 1 + help contextsize-stack + else + set $CONTEXTSIZE_STACK = $arg0 + end +end +document contextsize-stack +Syntax: contextsize-stack NUM +| Set stack dump window size to NUM lines. +end + + +define contextsize-data + if $argc != 1 + help contextsize-data + else + set $CONTEXTSIZE_DATA = $arg0 + end +end +document contextsize-data +Syntax: contextsize-data NUM +| Set data dump window size to NUM lines. +end + + +define contextsize-code + if $argc != 1 + help contextsize-code + else + set $CONTEXTSIZE_CODE = $arg0 + end +end +document contextsize-code +Syntax: contextsize-code NUM +| Set code window size to NUM lines. +end + + +# _____________breakpoint aliases_____________ +define bpl + info breakpoints +end +document bpl +Syntax: bpl +| List all breakpoints. +end + + +define bp + if $argc != 1 + help bp + else + if $ASLR != 0 + break ($arg0 + $ASLR) + else + break $arg0 + end + end +end +document bp +Syntax: bp LOCATION +| Set breakpoint. +| LOCATION may be a line number, function name, or "*" and an address. +| To break on a symbol you must enclose symbol name inside "". +| Example: +| bp "[NSControl stringValue]" +| Or else you can use directly the break command (break [NSControl stringValue]) +end + + +define bpc + if $argc != 1 + help bpc + else + clear $arg0 + end +end +document bpc +Syntax: bpc LOCATION +| Clear breakpoint. +| LOCATION may be a line number, function name, or "*" and an address. +end + + +define bpe + if $argc != 1 + help bpe + else + enable $arg0 + end +end +document bpe +Syntax: bpe NUM +| Enable breakpoint with number NUM. +end + + +define bpd + if $argc != 1 + help bpd + else + disable $arg0 + end +end +document bpd +Syntax: bpd NUM +| Disable breakpoint with number NUM. +end + + +define bpt + if $argc != 1 + help bpt + else + tbreak $arg0 + end +end +document bpt +Syntax: bpt LOCATION +| Set a temporary breakpoint. +| This breakpoint will be automatically deleted when hit!. +| LOCATION may be a line number, function name, or "*" and an address. +end + + +define bpm + if $argc != 1 + help bpm + else + awatch $arg0 + end +end +document bpm +Syntax: bpm EXPRESSION +| Set a read/write breakpoint on EXPRESSION, e.g. *address. +end + + +define bhb + if $argc != 1 + help bhb + else + hb $arg0 + end +end +document bhb +Syntax: bhb LOCATION +| Set hardware assisted breakpoint. +| LOCATION may be a line number, function name, or "*" and an address. +end + + +define bht + if $argc != 1 + help bht + else + thbreak $arg0 + end +end +document bht +Usage: bht LOCATION +| Set a temporary hardware breakpoint. +| This breakpoint will be automatically deleted when hit! +| LOCATION may be a line number, function name, or "*" and an address. +end + + +# ______________process information____________ +define argv + show args +end +document argv +Syntax: argv +| Print program arguments. +end + + +define stack + if $argc == 0 + info stack + end + if $argc == 1 + info stack $arg0 + end + if $argc > 1 + help stack + end +end +document stack +Syntax: stack +| Print backtrace of the call stack, or innermost COUNT frames. +end + + +define frame + info frame + info args + info locals +end +document frame +Syntax: frame +| Print stack frame. +end + + +define flagsarm +# conditional flags are +# negative/less than (N), bit 31 of CPSR +# zero (Z), bit 30 +# Carry/Borrow/Extend (C), bit 29 +# Overflow (V), bit 28 + # negative/less than (N), bit 31 of CPSR + if (($cpsr >> 0x1f) & 1) + printf "N " + set $_n_flag = 1 + else + printf "n " + set $_n_flag = 0 + end + # zero (Z), bit 30 + if (($cpsr >> 0x1e) & 1) + printf "Z " + set $_z_flag = 1 + else + printf "z " + set $_z_flag = 0 + end + # Carry/Borrow/Extend (C), bit 29 + if (($cpsr >> 0x1d) & 1) + printf "C " + set $_c_flag = 1 + else + printf "c " + set $_c_flag = 0 + end + # Overflow (V), bit 28 + if (($cpsr >> 0x1c) & 1) + printf "V " + set $_v_flag = 1 + else + printf "v " + set $_v_flag = 0 + end + # Sticky overflow (Q), bit 27 + if (($cpsr >> 0x1b) & 1) + printf "Q " + set $_q_flag = 1 + else + printf "q " + set $_q_flag = 0 + end + # Java state bit (J), bit 24 + # When T=1: + # J = 0 The processor is in Thumb state. + # J = 1 The processor is in ThumbEE state. + if (($cpsr >> 0x18) & 1) + printf "J " + set $_j_flag = 1 + else + printf "j " + set $_j_flag = 0 + end + # Data endianness bit (E), bit 9 + if (($cpsr >> 9) & 1) + printf "E " + set $_e_flag = 1 + else + printf "e " + set $_e_flag = 0 + end + # Imprecise abort disable bit (A), bit 8 + # The A bit is set to 1 automatically. It is used to disable imprecise data aborts. + # It might not be writable in the Nonsecure state if the AW bit in the SCR register is reset. + if (($cpsr >> 8) & 1) + printf "A " + set $_a_flag = 1 + else + printf "a " + set $_a_flag = 0 + end + # IRQ disable bit (I), bit 7 + # When the I bit is set to 1, IRQ interrupts are disabled. + if (($cpsr >> 7) & 1) + printf "I " + set $_i_flag = 1 + else + printf "i " + set $_i_flag = 0 + end + # FIQ disable bit (F), bit 6 + # When the F bit is set to 1, FIQ interrupts are disabled. + # FIQ can be nonmaskable in the Nonsecure state if the FW bit in SCR register is reset. + if (($cpsr >> 6) & 1) + printf "F " + set $_f_flag = 1 + else + printf "f " + set $_f_flag = 0 + end + # Thumb state bit (F), bit 5 + # if 1 then the processor is executing in Thumb state or ThumbEE state depending on the J bit + if (($cpsr >> 5) & 1) + printf "T " + set $_t_flag = 1 + else + printf "t " + set $_t_flag = 0 + end + # TODO: GE bit ? +end +document flagsarm +Syntax: flagsarm +| Auxiliary function to set ARM cpu flags. +end + + +define flagsx86 + # OF (overflow) flag + if (((unsigned int)$eflags >> 0xB) & 1) + printf "O " + set $_of_flag = 1 + else + printf "o " + set $_of_flag = 0 + end + # DF (direction) flag + if (((unsigned int)$eflags >> 0xA) & 1) + printf "D " + else + printf "d " + end + # IF (interrupt enable) flag + if (((unsigned int)$eflags >> 9) & 1) + printf "I " + else + printf "i " + end + # TF (trap) flag + if (((unsigned int)$eflags >> 8) & 1) + printf "T " + else + printf "t " + end + # SF (sign) flag + if (((unsigned int)$eflags >> 7) & 1) + printf "S " + set $_sf_flag = 1 + else + printf "s " + set $_sf_flag = 0 + end + # ZF (zero) flag + if (((unsigned int)$eflags >> 6) & 1) + printf "Z " + set $_zf_flag = 1 + else + printf "z " + set $_zf_flag = 0 + end + # AF (adjust) flag + if (((unsigned int)$eflags >> 4) & 1) + printf "A " + else + printf "a " + end + # PF (parity) flag + if (((unsigned int)$eflags >> 2) & 1) + printf "P " + set $_pf_flag = 1 + else + printf "p " + set $_pf_flag = 0 + end + # CF (carry) flag + if ((unsigned int)$eflags & 1) + printf "C " + set $_cf_flag = 1 + else + printf "c " + set $_cf_flag = 0 + end + printf "\n" +end +document flagsx86 +Syntax: flagsx86 +| Auxiliary function to set X86/X64 cpu flags. +end + + +define flags + # call the auxiliary functions based on target cpu + if $ARM == 1 + flagsarm + else + flagsx86 + end +end +document flags +Syntax: flags +| Print flags register. +end + + +define eflags + if $ARM == 1 + # http://www.heyrick.co.uk/armwiki/The_Status_register + printf " N <%d> Z <%d> C <%d> V <%d>",\ + (($cpsr >> 0x1f) & 1), (($cpsr >> 0x1e) & 1), \ + (($cpsr >> 0x1d) & 1), (($cpsr >> 0x1c) & 1) + printf " Q <%d> J <%d> GE <%d> E <%d> A <%d>",\ + (($cpsr >> 0x1b) & 1), (($cpsr >> 0x18) & 1),\ + (($cpsr >> 0x10) & 7), (($cpsr >> 9) & 1), (($cpsr >> 8) & 1) + printf " I <%d> F <%d> T <%d> \n",\ + (($cpsr >> 7) & 1), (($cpsr >> 6) & 1), \ + (($cpsr >> 5) & 1) + else + printf " OF <%d> DF <%d> IF <%d> TF <%d>",\ + (((unsigned int)$eflags >> 0xB) & 1), (((unsigned int)$eflags >> 0xA) & 1), \ + (((unsigned int)$eflags >> 9) & 1), (((unsigned int)$eflags >> 8) & 1) + printf " SF <%d> ZF <%d> AF <%d> PF <%d> CF <%d>\n",\ + (((unsigned int)$eflags >> 7) & 1), (((unsigned int)$eflags >> 6) & 1),\ + (((unsigned int)$eflags >> 4) & 1), (((unsigned int)$eflags >> 2) & 1), ((unsigned int)$eflags & 1) + printf " ID <%d> VIP <%d> VIF <%d> AC <%d>",\ + (((unsigned int)$eflags >> 0x15) & 1), (((unsigned int)$eflags >> 0x14) & 1), \ + (((unsigned int)$eflags >> 0x13) & 1), (((unsigned int)$eflags >> 0x12) & 1) + printf " VM <%d> RF <%d> NT <%d> IOPL <%d>\n",\ + (((unsigned int)$eflags >> 0x11) & 1), (((unsigned int)$eflags >> 0x10) & 1),\ + (((unsigned int)$eflags >> 0xE) & 1), (((unsigned int)$eflags >> 0xC) & 3) + end +end +document eflags +Syntax: eflags +| Print eflags register. +end + + +define cpsr + eflags +end +document cpsr +Syntax: cpsr +| Print cpsr register. +end + +define regarm + printf " " + # R0 + color $COLOR_REGNAME + printf "R0:" + if ($r0 != $oldr0 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r0 + # R1 + color $COLOR_REGNAME + printf "R1:" + if ($r1 != $oldr1 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r1 + # R2 + color $COLOR_REGNAME + printf "R2:" + if ($r2 != $oldr2 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r2 + # R3 + color $COLOR_REGNAME + printf "R3:" + if ($r3 != $oldr3 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X\n", $r3 + printf " " + # R4 + color $COLOR_REGNAME + printf "R4:" + if ($r4 != $oldr4 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r4 + # R5 + color $COLOR_REGNAME + printf "R5:" + if ($r5 != $oldr5 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r5 + # R6 + color $COLOR_REGNAME + printf "R6:" + if ($r6 != $oldr6 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r6 + # R7 + color $COLOR_REGNAME + printf "R7:" + if ($r7 != $oldr7 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X\n", $r7 + printf " " + # R8 + color $COLOR_REGNAME + printf "R8:" + if ($r8 != $oldr8 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r8 + # R9 + color $COLOR_REGNAME + printf "R9:" + if ($r9 != $oldr9 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r9 + # R10 + color $COLOR_REGNAME + printf "R10:" + if ($r10 != $oldr10 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r10 + # R11 + color $COLOR_REGNAME + printf "R11:" + if ($r11 != $oldr11 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $r11 + dumpjump + printf "\n" + # R12 + color $COLOR_REGNAME + printf " R12:" + if ($r12 != $oldr12 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X", $r12 + printf " " + # SP + color $COLOR_REGNAME + printf "SP:" + if ($sp != $oldsp && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $sp + # LR + color $COLOR_REGNAME + printf "LR:" + if ($lr != $oldlr && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $lr + # PC + color $COLOR_REGNAME + printf "PC:" + color $COLOR_REGVAL_MODIFIED + printf " 0x%08X ", $pc + color_bold + color_underline + color $COLOR_CPUFLAGS + flags + color_reset + printf "\n" +end +document regarm +Syntax: regarm +| Auxiliary function to display ARM registers. +end + +define regx64 + # 64bits stuff + printf " " + # RAX + color $COLOR_REGNAME + printf "RAX:" + if ($rax != $oldrax && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rax + # RBX + color $COLOR_REGNAME + printf "RBX:" + if ($rbx != $oldrbx && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rbx + # RBP + color $COLOR_REGNAME + printf "RBP:" + if ($rbp != $oldrbp && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rbp + # RSP + color $COLOR_REGNAME + printf "RSP:" + if ($rsp != $oldrsp && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rsp + color_bold + color_underline + color $COLOR_CPUFLAGS + flags + color_reset + printf " " + # RDI + color $COLOR_REGNAME + printf "RDI:" + if ($rdi != $oldrdi && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rdi + # RSI + color $COLOR_REGNAME + printf "RSI:" + if ($rsi != $oldrsi && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rsi + # RDX + color $COLOR_REGNAME + printf "RDX:" + if ($rdx != $oldrdx && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rdx + # RCX + color $COLOR_REGNAME + printf "RCX:" + if ($rcx != $oldrcx && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $rcx + # RIP + color $COLOR_REGNAME + printf "RIP:" + color $COLOR_REGVAL_MODIFIED + printf " 0x%016lX\n ", $rip + # R8 + color $COLOR_REGNAME + printf "R8 :" + if ($r8 != $oldr8 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $r8 + # R9 + color $COLOR_REGNAME + printf "R9 :" + if ($r9 != $oldr9 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $r9 + # R10 + color $COLOR_REGNAME + printf "R10:" + if ($r10 != $oldr10 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $r10 + # R11 + color $COLOR_REGNAME + printf "R11:" + if ($r11 != $oldr11 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $r11 + # R12 + color $COLOR_REGNAME + printf "R12:" + if ($r12 != $oldr12 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX\n ", $r12 + # R13 + color $COLOR_REGNAME + printf "R13:" + if ($r13 != $oldr13 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $r13 + # R14 + color $COLOR_REGNAME + printf "R14:" + if ($r14 != $oldr14 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX ", $r14 + # R15 + color $COLOR_REGNAME + printf "R15:" + if ($r15 != $oldr15 && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%016lX\n ", $r15 + color $COLOR_REGNAME + printf "CS:" + color $COLOR_REGVAL + printf " %04X ", $cs + color $COLOR_REGNAME + printf "DS:" + color $COLOR_REGVAL + printf " %04X ", $ds + color $COLOR_REGNAME + printf "ES:" + color $COLOR_REGVAL + printf " %04X ", $es + color $COLOR_REGNAME + printf "FS:" + color $COLOR_REGVAL + printf " %04X ", $fs + color $COLOR_REGNAME + printf "GS:" + color $COLOR_REGVAL + printf " %04X ", $gs + color $COLOR_REGNAME + printf "SS:" + color $COLOR_REGVAL + printf " %04X", $ss + color_reset +end +document regx64 +Syntax: regx64 +| Auxiliary function to display X86_64 registers. +end + + +define regx86 + printf " " + # EAX + color $COLOR_REGNAME + printf "EAX:" + if ($eax != $oldeax && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $eax + # EBX + color $COLOR_REGNAME + printf "EBX:" + if ($ebx != $oldebx && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $ebx + # ECX + color $COLOR_REGNAME + printf "ECX:" + if ($ecx != $oldecx && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $ecx + # EDX + color $COLOR_REGNAME + printf "EDX:" + if ($edx != $oldedx && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $edx + color_bold + color_underline + color $COLOR_CPUFLAGS + flags + color_reset + printf " " + # ESI + color $COLOR_REGNAME + printf "ESI:" + if ($esi != $oldesi && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $esi + # EDI + color $COLOR_REGNAME + printf "EDI:" + if ($edi != $oldedi && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $edi + # EBP + color $COLOR_REGNAME + printf "EBP:" + if ($ebp != $oldebp && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $ebp + # ESP + color $COLOR_REGNAME + printf "ESP:" + if ($esp != $oldesp && $SHOWREGCHANGES == 1) + color $COLOR_REGVAL_MODIFIED + else + color $COLOR_REGVAL + end + printf " 0x%08X ", $esp + # EIP + color $COLOR_REGNAME + printf "EIP:" + color $COLOR_REGVAL_MODIFIED + printf " 0x%08X\n ", $eip + color $COLOR_REGNAME + printf "CS:" + color $COLOR_REGVAL + printf " %04X ", $cs + color $COLOR_REGNAME + printf "DS:" + color $COLOR_REGVAL + printf " %04X ", $ds + color $COLOR_REGNAME + printf "ES:" + color $COLOR_REGVAL + printf " %04X ", $es + color $COLOR_REGNAME + printf "FS:" + color $COLOR_REGVAL + printf " %04X ", $fs + color $COLOR_REGNAME + printf "GS:" + color $COLOR_REGVAL + printf " %04X ", $gs + color $COLOR_REGNAME + printf "SS:" + color $COLOR_REGVAL + printf " %04X", $ss + color_reset +end +document regx86 +Syntax: regx86 +| Auxiliary function to display X86 registers. +end + + +define reg + if $ARM == 1 + regarm + if ($SHOWREGCHANGES == 1) + set $oldr0 = $r0 + set $oldr1 = $r1 + set $oldr2 = $r2 + set $oldr3 = $r3 + set $oldr4 = $r4 + set $oldr5 = $r5 + set $oldr6 = $r6 + set $oldr7 = $r7 + set $oldr8 = $r8 + set $oldr9 = $r9 + set $oldr10 = $r10 + set $oldr11 = $r11 + set $oldr12 = $r12 + set $oldsp = $sp + set $oldlr = $lr + end + else + if ($64BITS == 1) + regx64 + else + regx86 + end + # call smallregisters + smallregisters + # display conditional jump routine + if ($64BITS == 1) + printf "\t\t\t\t" + end + dumpjump + printf "\n" + if ($SHOWREGCHANGES == 1) + if ($64BITS == 1) + set $oldrax = $rax + set $oldrbx = $rbx + set $oldrcx = $rcx + set $oldrdx = $rdx + set $oldrsi = $rsi + set $oldrdi = $rdi + set $oldrbp = $rbp + set $oldrsp = $rsp + set $oldr8 = $r8 + set $oldr9 = $r9 + set $oldr10 = $r10 + set $oldr11 = $r11 + set $oldr12 = $r12 + set $oldr13 = $r13 + set $oldr14 = $r14 + set $oldr15 = $r15 + else + set $oldeax = $eax + set $oldebx = $ebx + set $oldecx = $ecx + set $oldedx = $edx + set $oldesi = $esi + set $oldedi = $edi + set $oldebp = $ebp + set $oldesp = $esp + end + end + end +end +document reg +Syntax: reg +| Print CPU registers. +end + + +define smallregisters + if ($64BITS == 1) + #64bits stuff + # from rax + set $eax = $rax & 0xffffffff + set $ax = $rax & 0xffff + set $al = $ax & 0xff + set $ah = $ax >> 8 + # from rbx + set $ebx = $rbx & 0xffffffff + set $bx = $rbx & 0xffff + set $bl = $bx & 0xff + set $bh = $bx >> 8 + # from rcx + set $ecx = $rcx & 0xffffffff + set $cx = $rcx & 0xffff + set $cl = $cx & 0xff + set $ch = $cx >> 8 + # from rdx + set $edx = $rdx & 0xffffffff + set $dx = $rdx & 0xffff + set $dl = $dx & 0xff + set $dh = $dx >> 8 + # from rsi + set $esi = $rsi & 0xffffffff + set $si = $rsi & 0xffff + # from rdi + set $edi = $rdi & 0xffffffff + set $di = $rdi & 0xffff + #32 bits stuff + else + # from eax + set $ax = $eax & 0xffff + set $al = $ax & 0xff + set $ah = $ax >> 8 + # from ebx + set $bx = $ebx & 0xffff + set $bl = $bx & 0xff + set $bh = $bx >> 8 + # from ecx + set $cx = $ecx & 0xffff + set $cl = $cx & 0xff + set $ch = $cx >> 8 + # from edx + set $dx = $edx & 0xffff + set $dl = $dx & 0xff + set $dh = $dx >> 8 + # from esi + set $si = $esi & 0xffff + # from edi + set $di = $edi & 0xffff + end +end +document smallregisters +Syntax: smallregisters +| Create the 16 and 8 bit cpu registers (gdb doesn't have them by default). +| And 32bits if we are dealing with 64bits binaries. +end + + +define func + if $argc == 0 + info functions + end + if $argc == 1 + info functions $arg0 + end + if $argc > 1 + help func + end +end +document func +Syntax: func +| Print all function names in target, or those matching REGEXP. +end + + +define var + if $argc == 0 + info variables + end + if $argc == 1 + info variables $arg0 + end + if $argc > 1 + help var + end +end +document var +Syntax: var +| Print all global and static variable names (symbols), or those matching REGEXP. +end + + +define lib + info sharedlibrary +end +document lib +Syntax: lib +| Print shared libraries linked to target. +end + + +define sig + if $argc == 0 + info signals + end + if $argc == 1 + info signals $arg0 + end + if $argc > 1 + help sig + end +end +document sig +Syntax: sig +| Print what debugger does when program gets various signals. +| Specify a SIGNAL as argument to print info on that signal only. +end + + +define threads + info threads +end +document threads +Syntax: threads +| Print threads in target. +end + + +define dis + if $argc == 0 + disassemble + end + if $argc == 1 + disassemble $arg0 + end + if $argc == 2 + disassemble $arg0 $arg1 + end + if $argc > 2 + help dis + end +end +document dis +Syntax: dis +| Disassemble a specified section of memory. +| Default is to disassemble the function surrounding the PC (program counter) of selected frame. +| With one argument, ADDR1, the function surrounding this address is dumped. +| Two arguments are taken as a range of memory to dump. +end + + +# __________hex/ascii dump an address_________ +define ascii_char + if $argc != 1 + help ascii_char + else + # thanks elaine :) + set $_c = *(unsigned char *)($arg0) + if ($_c < 0x20 || $_c > 0x7E) + printf "." + else + printf "%c", $_c + end + end +end +document ascii_char +Syntax: ascii_char ADDR +| Print ASCII value of byte at address ADDR. +| Print "." if the value is unprintable. +end + + +define hex_quad + if $argc != 1 + help hex_quad + else + printf "%02X %02X %02X %02X %02X %02X %02X %02X", \ + *(unsigned char*)($arg0), *(unsigned char*)($arg0 + 1), \ + *(unsigned char*)($arg0 + 2), *(unsigned char*)($arg0 + 3), \ + *(unsigned char*)($arg0 + 4), *(unsigned char*)($arg0 + 5), \ + *(unsigned char*)($arg0 + 6), *(unsigned char*)($arg0 + 7) + end +end +document hex_quad +Syntax: hex_quad ADDR +| Print eight hexadecimal bytes starting at address ADDR. +end + + +define hexdump + if $argc == 1 + hexdump_aux $arg0 + else + if $argc == 2 + set $_count = 0 + while ($_count < $arg1) + set $_i = ($_count * 0x10) + hexdump_aux $arg0+$_i + set $_count++ + end + else + help hexdump + end + end +end +document hexdump +Syntax: hexdump ADDR +| Display a 16-byte hex/ASCII dump of memory starting at address ADDR. +| Optional parameter is the number of lines to display if you want more than one. +end + + +define hexdump_aux + if $argc != 1 + help hexdump_aux + else + color_bold + if ($64BITS == 1) + printf "0x%016lX : ", $arg0 + else + printf "0x%08X : ", $arg0 + end + color_reset + hex_quad $arg0 + color_bold + printf " - " + color_reset + hex_quad $arg0+8 + printf " " + color_bold + ascii_char $arg0+0x0 + ascii_char $arg0+0x1 + ascii_char $arg0+0x2 + ascii_char $arg0+0x3 + ascii_char $arg0+0x4 + ascii_char $arg0+0x5 + ascii_char $arg0+0x6 + ascii_char $arg0+0x7 + ascii_char $arg0+0x8 + ascii_char $arg0+0x9 + ascii_char $arg0+0xA + ascii_char $arg0+0xB + ascii_char $arg0+0xC + ascii_char $arg0+0xD + ascii_char $arg0+0xE + ascii_char $arg0+0xF + color_reset + printf "\n" + end +end +document hexdump_aux +Syntax: hexdump_aux ADDR +| Display a 16-byte hex/ASCII dump of memory at address ADDR. +end + + +# _______________data window__________________ +define ddump + if $argc != 1 + help ddump + else + color $COLOR_SEPARATOR + if $ARM == 1 + printf "[0x%08X]", $data_addr + else + if ($64BITS == 1) + printf "[0x%04X:0x%016lX]", $ds, $data_addr + else + printf "[0x%04X:0x%08X]", $ds, $data_addr + end + end + + color $COLOR_SEPARATOR + printf "------------------------" + printf "-------------------------------" + if ($64BITS == 1) + printf "-------------------------------------" + end + color_bold + color $COLOR_SEPARATOR + printf "[data]\n" + color_reset + set $_count = 0 + while ($_count < $arg0) + set $_i = ($_count * 0x10) + hexdump $data_addr+$_i + set $_count++ + end + end +end +document ddump +Syntax: ddump NUM +| Display NUM lines of hexdump for address in $data_addr global variable. +end + + +define dd + if $argc != 1 + help dd + else + set $data_addr = $arg0 + ddump 0x10 + end +end +document dd +Syntax: dd ADDR +| Display 16 lines of a hex dump of address starting at ADDR. +end + + +define datawin + if $ARM == 1 + if ((($r0 >> 0x18) == 0x40) || (($r0 >> 0x18) == 0x08) || (($r0 >> 0x18) == 0xBF)) + set $data_addr = $r0 + else + if ((($r1 >> 0x18) == 0x40) || (($r1 >> 0x18) == 0x08) || (($r1 >> 0x18) == 0xBF)) + set $data_addr = $r1 + else + if ((($r2 >> 0x18) == 0x40) || (($r2 >> 0x18) == 0x08) || (($r2 >> 0x18) == 0xBF)) + set $data_addr = $r2 + else + set $data_addr = $sp + end + end + end +################################# X86 + else + if ($64BITS == 1) + if ((($rsi >> 0x18) == 0x40) || (($rsi >> 0x18) == 0x08) || (($rsi >> 0x18) == 0xBF)) + set $data_addr = $rsi + else + if ((($rdi >> 0x18) == 0x40) || (($rdi >> 0x18) == 0x08) || (($rdi >> 0x18) == 0xBF)) + set $data_addr = $rdi + else + if ((($rax >> 0x18) == 0x40) || (($rax >> 0x18) == 0x08) || (($rax >> 0x18) == 0xBF)) + set $data_addr = $rax + else + set $data_addr = $rsp + end + end + end + else + if ((($esi >> 0x18) == 0x40) || (($esi >> 0x18) == 0x08) || (($esi >> 0x18) == 0xBF)) + set $data_addr = $esi + else + if ((($edi >> 0x18) == 0x40) || (($edi >> 0x18) == 0x08) || (($edi >> 0x18) == 0xBF)) + set $data_addr = $edi + else + if ((($eax >> 0x18) == 0x40) || (($eax >> 0x18) == 0x08) || (($eax >> 0x18) == 0xBF)) + set $data_addr = $eax + else + set $data_addr = $esp + end + end + end + end + end + ddump $CONTEXTSIZE_DATA +end +document datawin +Syntax: datawin +| Display valid address from one register in data window. +| Registers to choose are: esi, edi, eax, or esp. +end + + +################################ +##### ALERT ALERT ALERT ######## +################################ +# Huge mess going here :) HAHA # +################################ +define dumpjump + if $ARM == 1 + ## Most ARM and Thumb instructions are conditional! + # each instruction is 32 bits long + # 4 bits are for condition codes (16 in total) (bits 31:28 in ARM contain the condition or 1111 if instruction is unconditional) + # 2x4 bits for destination and first operand registers + # one for the set-status flag + # an assorted number for other stuff + # 12 bits for any immediate value + # $_t_flag == 0 => ARM mode + # $_t_flag == 1 => Thumb or ThumbEE + # State bit (T), bit 5 + if (($cpsr >> 5) & 1) + set $_t_flag = 1 + else + set $_t_flag = 0 + end + + if $_t_flag == 0 + set $_lastbyte = *(unsigned char *)($pc+3) + #set $_bit31 = ($_lastbyte >> 7) & 1 + #set $_bit30 = ($_lastbyte >> 6) & 1 + #set $_bit29 = ($_lastbyte >> 5) & 1 + #set $_bit28 = ($_lastbyte >> 4) & 1 + set $_conditional = $_lastbyte >> 4 + dumpjumphelper + else + # if bits 15-12 (opcode in Thumb instructions) are equal to 1 1 0 1 (0xD) then we have a conditional branch + # bits 11-8 for the conditional execution code (check ARMv7 manual A8.3) + if ( (*(unsigned char *)($pc+1) >> 4) == 0xD ) + set $_conditional = *(unsigned char *)($pc+1) ^ 0xD0 + dumpjumphelper + end + end +##################### X86 + else + ## grab the first two bytes from the instruction so we can determine the jump instruction + set $_byte1 = *(unsigned char *)$pc + set $_byte2 = *(unsigned char *)($pc+1) + ## and now check what kind of jump we have (in case it's a jump instruction) + ## I changed the flags routine to save the flag into a variable, so we don't need to repeat the process :) (search for "define flags") + + ## opcode 0x77: JA, JNBE (jump if CF=0 and ZF=0) + ## opcode 0x0F87: JNBE, JA + if ( ($_byte1 == 0x77) || ($_byte1 == 0x0F && $_byte2 == 0x87) ) + # cf=0 and zf=0 + if ($_cf_flag == 0 && $_zf_flag == 0) + color $RED + printf " Jump is taken (c=0 and z=0)" + else + # cf != 0 or zf != 0 + color $RED + printf " Jump is NOT taken (c!=0 or z!=0)" + end + end + ## opcode 0x73: JAE, JNB, JNC (jump if CF=0) + ## opcode 0x0F83: JNC, JNB, JAE (jump if CF=0) + if ( ($_byte1 == 0x73) || ($_byte1 == 0x0F && $_byte2 == 0x83) ) + # cf=0 + if ($_cf_flag == 0) + color $RED + printf " Jump is taken (c=0)" + else + # cf != 0 + color $RED + printf " Jump is NOT taken (c!=0)" + end + end + ## opcode 0x72: JB, JC, JNAE (jump if CF=1) + ## opcode 0x0F82: JNAE, JB, JC + if ( ($_byte1 == 0x72) || ($_byte1 == 0x0F && $_byte2 == 0x82) ) + # cf=1 + if ($_cf_flag == 1) + color $RED + printf " Jump is taken (c=1)" + else + # cf != 1 + color $RED + printf " Jump is NOT taken (c!=1)" + end + end + ## opcode 0x76: JBE, JNA (jump if CF=1 or ZF=1) + ## opcode 0x0F86: JBE, JNA + if ( ($_byte1 == 0x76) || ($_byte1 == 0x0F && $_byte2 == 0x86) ) + # cf=1 or zf=1 + if (($_cf_flag == 1) || ($_zf_flag == 1)) + color $RED + printf " Jump is taken (c=1 or z=1)" + else + # cf != 1 or zf != 1 + color $RED + printf " Jump is NOT taken (c!=1 or z!=1)" + end + end + ## opcode 0xE3: JCXZ, JECXZ, JRCXZ (jump if CX=0 or ECX=0 or RCX=0) + if ($_byte1 == 0xE3) + # cx=0 or ecx=0 + if (($ecx == 0) || ($cx == 0)) + color $RED + printf " Jump is taken (cx=0 or ecx=0)" + else + color $RED + printf " Jump is NOT taken (cx!=0 or ecx!=0)" + end + end + ## opcode 0x74: JE, JZ (jump if ZF=1) + ## opcode 0x0F84: JZ, JE, JZ (jump if ZF=1) + if ( ($_byte1 == 0x74) || ($_byte1 == 0x0F && $_byte2 == 0x84) ) + # ZF = 1 + if ($_zf_flag == 1) + color $RED + printf " Jump is taken (z=1)" + else + # ZF = 0 + color $RED + printf " Jump is NOT taken (z!=1)" + end + end + ## opcode 0x7F: JG, JNLE (jump if ZF=0 and SF=OF) + ## opcode 0x0F8F: JNLE, JG (jump if ZF=0 and SF=OF) + if ( ($_byte1 == 0x7F) || ($_byte1 == 0x0F && $_byte2 == 0x8F) ) + # zf = 0 and sf = of + if (($_zf_flag == 0) && ($_sf_flag == $_of_flag)) + color $RED + printf " Jump is taken (z=0 and s=o)" + else + color $RED + printf " Jump is NOT taken (z!=0 or s!=o)" + end + end + ## opcode 0x7D: JGE, JNL (jump if SF=OF) + ## opcode 0x0F8D: JNL, JGE (jump if SF=OF) + if ( ($_byte1 == 0x7D) || ($_byte1 == 0x0F && $_byte2 == 0x8D) ) + # sf = of + if ($_sf_flag == $_of_flag) + color $RED + printf " Jump is taken (s=o)" + else + color $RED + printf " Jump is NOT taken (s!=o)" + end + end + ## opcode: 0x7C: JL, JNGE (jump if SF != OF) + ## opcode: 0x0F8C: JNGE, JL (jump if SF != OF) + if ( ($_byte1 == 0x7C) || ($_byte1 == 0x0F && $_byte2 == 0x8C) ) + # sf != of + if ($_sf_flag != $_of_flag) + color $RED + printf " Jump is taken (s!=o)" + else + color $RED + printf " Jump is NOT taken (s=o)" + end + end + ## opcode 0x7E: JLE, JNG (jump if ZF = 1 or SF != OF) + ## opcode 0x0F8E: JNG, JLE (jump if ZF = 1 or SF != OF) + if ( ($_byte1 == 0x7E) || ($_byte1 == 0x0F && $_byte2 == 0x8E) ) + # zf = 1 or sf != of + if (($_zf_flag == 1) || ($_sf_flag != $_of_flag)) + color $RED + printf " Jump is taken (zf=1 or sf!=of)" + else + color $RED + printf " Jump is NOT taken (zf!=1 or sf=of)" + end + end + ## opcode 0x75: JNE, JNZ (jump if ZF = 0) + ## opcode 0x0F85: JNE, JNZ (jump if ZF = 0) + if ( ($_byte1 == 0x75) || ($_byte1 == 0x0F && $_byte2 == 0x85) ) + # ZF = 0 + if ($_zf_flag == 0) + color $RED + printf " Jump is taken (z=0)" + else + # ZF = 1 + color $RED + printf " Jump is NOT taken (z!=0)" + end + end + ## opcode 0x71: JNO (OF = 0) + ## opcode 0x0F81: JNO (OF = 0) + if ( ($_byte1 == 0x71) || ($_byte1 == 0x0F && $_byte2 == 0x81) ) + # OF = 0 + if ($_of_flag == 0) + color $RED + printf " Jump is taken (o=0)" + else + # OF != 0 + color $RED + printf " Jump is NOT taken (o!=0)" + end + end + ## opcode 0x7B: JNP, JPO (jump if PF = 0) + ## opcode 0x0F8B: JPO (jump if PF = 0) + if ( ($_byte1 == 0x7B) || ($_byte1 == 0x0F && $_byte2 == 0x8B) ) + # PF = 0 + if ($_pf_flag == 0) + color $RED + printf " Jump is NOT taken (p=0)" + else + # PF != 0 + color $RED + printf " Jump is taken (p!=0)" + end + end + ## opcode 0x79: JNS (jump if SF = 0) + ## opcode 0x0F89: JNS (jump if SF = 0) + if ( ($_byte1 == 0x79) || ($_byte1 == 0x0F && $_byte2 == 0x89) ) + # SF = 0 + if ($_sf_flag == 0) + color $RED + printf " Jump is taken (s=0)" + else + # SF != 0 + color $RED + printf " Jump is NOT taken (s!=0)" + end + end + ## opcode 0x70: JO (jump if OF=1) + ## opcode 0x0F80: JO (jump if OF=1) + if ( ($_byte1 == 0x70) || ($_byte1 == 0x0F && $_byte2 == 0x80) ) + # OF = 1 + if ($_of_flag == 1) + color $RED + printf " Jump is taken (o=1)" + else + # OF != 1 + color $RED + printf " Jump is NOT taken (o!=1)" + end + end + ## opcode 0x7A: JP, JPE (jump if PF=1) + ## opcode 0x0F8A: JP, JPE (jump if PF=1) + if ( ($_byte1 == 0x7A) || ($_byte1 == 0x0F && $_byte2 == 0x8A) ) + # PF = 1 + if ($_pf_flag == 1) + color $RED + printf " Jump is taken (p=1)" + else + # PF = 0 + color $RED + printf " Jump is NOT taken (p!=1)" + end + end + ## opcode 0x78: JS (jump if SF=1) + ## opcode 0x0F88: JS (jump if SF=1) + if ( ($_byte1 == 0x78) || ($_byte1 == 0x0F && $_byte2 == 0x88) ) + # SF = 1 + if ($_sf_flag == 1) + color $RED + printf " Jump is taken (s=1)" + else + # SF != 1 + color $RED + printf " Jump is NOT taken (s!=1)" + end + end + end +end +document dumpjump +Syntax: dumpjump +| Display if conditional jump will be taken or not. +end + +define dumpjumphelper + # 0000 - EQ: Z == 1 + if ($_conditional == 0x0) + if ($_z_flag == 1) + color $RED + printf " Jump is taken (z==1)" + else + color $RED + printf " Jump is NOT taken (z!=1)" + end + end + # 0001 - NE: Z == 0 + if ($_conditional == 0x1) + if ($_z_flag == 0) + color $RED + printf " Jump is taken (z==0)" + else + color $RED + printf " Jump is NOT taken (z!=0)" + end + end + # 0010 - CS: C == 1 + if ($_conditional == 0x2) + if ($_c_flag == 1) + color $RED + printf " Jump is taken (c==1)" + else + color $RED + printf " Jump is NOT taken (c!=1)" + end + end + # 0011 - CC: C == 0 + if ($_conditional == 0x3) + if ($_c_flag == 0) + color $RED + printf " Jump is taken (c==0)" + else + color $RED + printf " Jump is NOT taken (c!=0)" + end + end + # 0100 - MI: N == 1 + if ($_conditional == 0x4) + if ($_n_flag == 1) + color $RED + printf " Jump is taken (n==1)" + else + color $RED + printf " Jump is NOT taken (n!=1)" + end + end + # 0101 - PL: N == 0 + if ($_conditional == 0x5) + if ($_n_flag == 0) + color $RED + printf " Jump is taken (n==0)" + else + color $RED + printf " Jump is NOT taken (n!=0)" + end + end + # 0110 - VS: V == 1 + if ($_conditional == 0x6) + if ($_v_flag == 1) + color $RED + printf " Jump is taken (v==1)" + else + color $RED + printf " Jump is NOT taken (v!=1)" + end + end + # 0111 - VC: V == 0 + if ($_conditional == 0x7) + if ($_v_flag == 0) + color $RED + printf " Jump is taken (v==0)" + else + color $RED + printf " Jump is NOT taken (v!=0)" + end + end + # 1000 - HI: C == 1 and Z == 0 + if ($_conditional == 0x8) + if ($_c_flag == 1 && $_z_flag == 0) + color $RED + printf " Jump is taken (c==1 and z==0)" + else + color $RED + printf " Jump is NOT taken (c!=1 or z!=0)" + end + end + # 1001 - LS: C == 0 or Z == 1 + if ($_conditional == 0x9) + if ($_c_flag == 0 || $_z_flag == 1) + color $RED + printf " Jump is taken (c==0 or z==1)" + else + color $RED + printf " Jump is NOT taken (c!=0 or z!=1)" + end + end + # 1010 - GE: N == V + if ($_conditional == 0xA) + if ($_n_flag == $_v_flag) + color $RED + printf " Jump is taken (n==v)" + else + color $RED + printf " Jump is NOT taken (n!=v)" + end + end + # 1011 - LT: N != V + if ($_conditional == 0xB) + if ($_n_flag != $_v_flag) + color $RED + printf " Jump is taken (n!=v)" + else + color $RED + printf " Jump is NOT taken (n==v)" + end + end + # 1100 - GT: Z == 0 and N == V + if ($_conditional == 0xC) + if ($_z_flag == 0 && $_n_flag == $_v_flag) + color $RED + printf " Jump is taken (z==0 and n==v)" + else + color $RED + printf " Jump is NOT taken (z!=0 or n!=v)" + end + end + # 1101 - LE: Z == 1 or N != V + if ($_conditional == 0xD) + if ($_z_flag == 1 || $_n_flag != $_v_flag) + color $RED + printf " Jump is taken (z==1 or n!=v)" + else + color $RED + printf " Jump is NOT taken (z!=1 or n==v)" + end + end +end +document dumpjumphelper +Syntax: dumpjumphelper +| Helper function to decide if conditional jump will be taken or not, for ARM and Thumb. +end + + +# _______________process context______________ +# initialize variable +set $displayobjectivec = 0 + +define context + color $COLOR_SEPARATOR + if $SHOWCPUREGISTERS == 1 + printf "----------------------------------------" + printf "----------------------------------" + if ($64BITS == 1) + printf "---------------------------------------------" + end + color $COLOR_SEPARATOR + color_bold + printf "[regs]\n" + color_reset + reg + color $CYAN + end + if $SHOWSTACK == 1 + color $COLOR_SEPARATOR + if $ARM == 1 + printf "[0x%08X]", $sp + else + if ($64BITS == 1) + printf "[0x%04X:0x%016lX]", $ss, $rsp + else + printf "[0x%04X:0x%08X]", $ss, $esp + end + end + color $COLOR_SEPARATOR + printf "-------------------------" + printf "-----------------------------" + if ($64BITS == 1) + printf "-------------------------------------" + end + color $COLOR_SEPARATOR + color_bold + printf "[stack]\n" + color_reset + set $context_i = $CONTEXTSIZE_STACK + while ($context_i > 0) + set $context_t = $sp + 0x10 * ($context_i - 1) + hexdump $context_t + set $context_i-- + end + end + # show the objective C message being passed to msgSend + if $SHOWOBJECTIVEC == 1 + #FIXME: X64 and ARM + # What a piece of crap that's going on here :) + # detect if it's the correct opcode we are searching for + if $ARM == 0 + set $__byte1 = *(unsigned char *)$pc + set $__byte = *(int *)$pc + if ($__byte == 0x4244489) + set $objectivec = $eax + set $displayobjectivec = 1 + end + + if ($__byte == 0x4245489) + set $objectivec = $edx + set $displayobjectivec = 1 + end + + if ($__byte == 0x4244c89) + set $objectivec = $ecx + set $displayobjectivec = 1 + end + else + set $__byte1 = 0 + end + # and now display it or not (we have no interest in having the info displayed after the call) + if $__byte1 == 0xE8 + if $displayobjectivec == 1 + color $COLOR_SEPARATOR + printf "--------------------------------------------------------------------" + if ($64BITS == 1) + printf "---------------------------------------------" + end + color $COLOR_SEPARATOR + color_bold + printf "[ObjectiveC]\n" + color_reset + color $BLACK + x/s $objectivec + end + set $displayobjectivec = 0 + end + if $displayobjectivec == 1 + color $COLOR_SEPARATOR + printf "--------------------------------------------------------------------" + if ($64BITS == 1) + printf "---------------------------------------------" + end + color $COLOR_SEPARATOR + color_bold + printf "[ObjectiveC]\n" + color_reset + color $BLACK + x/s $objectivec + end + end + color_reset +# and this is the end of this little crap + + if $SHOWDATAWIN == 1 + datawin + end + if $SHOWDISASM == 1 + color $COLOR_SEPARATOR + printf "--------------------------------------------------------------------------" + if ($64BITS == 1) + printf "---------------------------------------------" + end + color $COLOR_SEPARATOR + color_bold + printf "[code]\n" + color_reset + set $context_i = $CONTEXTSIZE_CODE + if ($context_i > 0) + if ($SETCOLOR1STLINE == 1) + color $GREEN + if ($ARM == 1) + # | $cpsr.t (Thumb flag) + x/i (unsigned int)$pc | (($cpsr >> 5) & 1) + else + x/i $pc + end + color_reset + else + if ($ARM == 1) + # | $cpsr.t (Thumb flag) + x/i (unsigned int)$pc | (($cpsr >> 5) & 1) + else + x/i $pc + end + end + set $context_i-- + end + while ($context_i > 0) + x /i + set $context_i-- + end + end + color $COLOR_SEPARATOR + printf "----------------------------------------" + printf "----------------------------------------" + if ($64BITS == 1) + printf "---------------------------------------------\n" + else + printf "\n" + end + color_reset +end +document context +Syntax: context +| Print context window, i.e. regs, stack, ds:esi and disassemble cs:eip. +end + + +define context-on + set $SHOW_CONTEXT = 1 + printf "Displaying of context is now ON\n" +end +document context-on +Syntax: context-on +| Enable display of context on every program break. +end + + +define context-off + set $SHOW_CONTEXT = 0 + printf "Displaying of context is now OFF\n" +end +document context-off +Syntax: context-off +| Disable display of context on every program break. +end + + +# _______________process control______________ +define n + if $argc == 0 + nexti + end + if $argc == 1 + nexti $arg0 + end + if $argc > 1 + help n + end +end +document n +Syntax: n +| Step one instruction, but proceed through subroutine calls. +| If NUM is given, then repeat it NUM times or till program stops. +| This is alias for nexti. +end + + +define go + if $argc == 0 + stepi + end + if $argc == 1 + stepi $arg0 + end + if $argc > 1 + help go + end +end +document go +Syntax: go +| Step one instruction exactly. +| If NUM is given, then repeat it NUM times or till program stops. +| This is alias for stepi. +end + + +define pret + finish +end +document pret +Syntax: pret +| Execute until selected stack frame returns (step out of current call). +| Upon return, the value returned is printed and put in the value history. +end + + +define init + set $SHOW_NEST_INSN = 0 + tbreak _init + r +end +document init +Syntax: init +| Run program and break on _init(). +end + + +define start + set $SHOW_NEST_INSN = 0 + tbreak _start + r +end +document start +Syntax: start +| Run program and break on _start(). +end + + +define sstart + set $SHOW_NEST_INSN = 0 + tbreak __libc_start_main + r +end +document sstart +Syntax: sstart +| Run program and break on __libc_start_main(). +| Useful for stripped executables. +end + + +define main + set $SHOW_NEST_INSN = 0 + tbreak main + r +end +document main +Syntax: main +| Run program and break on main(). +end + + +# FIXME64 +#### WARNING ! WARNING !! +#### More more messy stuff starting !!! +#### I was thinking about how to do this and then it ocurred me that it could be as simple as this ! :) +define stepoframework + if $ARM == 1 + # bl and bx opcodes + # bx Rn => ARM bits 27-20: 0 0 0 1 0 0 1 0 , bits 7-4: 0 0 0 1 ; Thumb bits: 15-7: 0 1 0 0 0 1 1 1 0 + # blx Rn => ARM bits 27-20: 0 0 0 1 0 0 1 0 , bits 7-4: 0 0 1 1 ; Thumb bits: 15-7: 0 1 0 0 0 1 1 1 1 + # bl # => ARM bits 27-24: 1 0 1 1 ; Thumb bits: 15-11: 1 1 1 1 0 + # blx # => ARM bits 31-25: 1 1 1 1 1 0 1 ; Thumb bits: 15-11: 1 1 1 1 0 + set $_nextaddress = 0 + + # ARM Mode + if ($_t_flag == 0) + set $_branchesint = *(unsigned int*)$pc + set $_bit31 = ($_branchesint >> 0x1F) & 1 + set $_bit30 = ($_branchesint >> 0x1E) & 1 + set $_bit29 = ($_branchesint >> 0x1D) & 1 + set $_bit28 = ($_branchesint >> 0x1C) & 1 + set $_bit27 = ($_branchesint >> 0x1B) & 1 + set $_bit26 = ($_branchesint >> 0x1A) & 1 + set $_bit25 = ($_branchesint >> 0x19) & 1 + set $_bit24 = ($_branchesint >> 0x18) & 1 + set $_bit23 = ($_branchesint >> 0x17) & 1 + set $_bit22 = ($_branchesint >> 0x16) & 1 + set $_bit21 = ($_branchesint >> 0x15) & 1 + set $_bit20 = ($_branchesint >> 0x14) & 1 + set $_bit7 = ($_branchesint >> 0x7) & 1 + set $_bit6 = ($_branchesint >> 0x6) & 1 + set $_bit5 = ($_branchesint >> 0x5) & 1 + set $_bit4 = ($_branchesint >> 0x4) & 1 + + # set $_lastbyte = *(unsigned char *)($pc+3) + # set $_bits2724 = $_lastbyte & 0x1 + # set $_bits3128 = $_lastbyte >> 4 + # if ($_bits3128 == 0xF) + # set $_bits2724 = $_lastbyte & 0xA + # set $_bits2724 = $_bits2724 >> 1 + # end + # set $_previousbyte = *(unsigned char *)($pc+2) + # set $_bits2320 = $_previousbyte >> 4 + # printf "bits2724: %x bits2320: %x\n", $_bits2724, $_bits2320 + + if ($_bit27 == 0 && $_bit26 == 0 && $_bit25 == 0 && $_bit24 == 1 && $_bit23 == 0 && $_bit22 == 0 && $_bit21 == 1 && $_bit20 == 0 && $_bit7 == 0 && $_bit6 == 0 && $_bit5 == 0 && $_bit4 == 1) + printf "Found a bx Rn\n" + set $_nextaddress = $pc+0x4 + end + if ($_bit27 == 0 && $_bit26 == 0 && $_bit25 == 0 && $_bit24 == 1 && $_bit23 == 0 && $_bit22 == 0 && $_bit21 == 1 && $_bit20 == 0 && $_bit7 == 0 && $_bit6 == 0 && $_bit5 == 1 && $_bit4 == 1) + printf "Found a blx Rn\n" + set $_nextaddress = $pc+0x4 + end + if ($_bit27 == 1 && $_bit26 == 0 && $_bit25 == 1 && $_bit24 == 1) + printf "Found a bl #\n" + set $_nextaddress = $pc+0x4 + end + if ($_bit31 == 1 && $_bit30 == 1 && $_bit29 == 1 && $_bit28 == 1 && $_bit27 == 1 && $_bit26 == 0 && $_bit25 == 1) + printf "Found a blx #\n" + set $_nextaddress = $pc+0x4 + end + # Thumb Mode + else + # 32 bits instructions in Thumb are divided into two half words + set $_hw1 = *(unsigned short*)($pc) + set $_hw2 = *(unsigned short*)($pc+2) + + # bl/blx (immediate) + # hw1: bits 15-11: 1 1 1 1 0 + # hw2: bits 15-14: 1 1 ; BL bit 12: 1 ; BLX bit 12: 0 + if ( ($_hw1 >> 0xC) == 0xF && (($_hw1 >> 0xB) & 1) == 0) + if ( ((($_hw2 >> 0xF) & 1) == 1) && ((($_hw2 >> 0xE) & 1) == 1) ) + set $_nextaddress = $pc+0x4 + end + end + end + # if we have found a call to bypass we set a temporary breakpoint on next instruction and continue + if ($_nextaddress != 0) + tbreak *$_nextaddress + continue + printf "[StepO] Next address will be %x\n", $_nextaddress + # else we just single step + else + nexti + end +###################################### X86 + else + ## we know that an opcode starting by 0xE8 has a fixed length + ## for the 0xFF opcodes, we can enumerate what is possible to have + # first we grab the first 3 bytes from the current program counter + set $_byte1 = *(unsigned char *)$pc + set $_byte2 = *(unsigned char *)($pc+1) + set $_byte3 = *(unsigned char *)($pc+2) + # and start the fun + # if it's a 0xE8 opcode, the total instruction size will be 5 bytes + # so we can simply calculate the next address and use a temporary breakpoint ! Voila :) + set $_nextaddress = 0 + # this one is the must useful for us !!! + if ($_byte1 == 0xE8) + set $_nextaddress = $pc + 0x5 + else + # just other cases we might be interested in... maybe this should be removed since the 0xE8 opcode is the one we will use more + # this is a big fucking mess and can be improved for sure :) I don't like the way it is ehehehe + if ($_byte1 == 0xFF) + # call *%eax (0xFFD0) || call *%edx (0xFFD2) || call *(%ecx) (0xFFD1) || call (%eax) (0xFF10) || call *%esi (0xFFD6) || call *%ebx (0xFFD3) || call DWORD PTR [edx] (0xFF12) + if ($_byte2 == 0xD0 || $_byte2 == 0xD1 || $_byte2 == 0xD2 || $_byte2 == 0xD3 || $_byte2 == 0xD6 || $_byte2 == 0x10 || $_byte2 == 0x11 || $_byte2 == 0xD7 || $_byte2 == 0x12) + set $_nextaddress = $pc + 0x2 + end + # call *0x??(%ebp) (0xFF55??) || call *0x??(%esi) (0xFF56??) || call *0x??(%edi) (0xFF5F??) || call *0x??(%ebx) + # call *0x??(%edx) (0xFF52??) || call *0x??(%ecx) (0xFF51??) || call *0x??(%edi) (0xFF57??) || call *0x??(%eax) (0xFF50??) + if ($_byte2 == 0x55 || $_byte2 == 0x56 || $_byte2 == 0x5F || $_byte2 == 0x53 || $_byte2 == 0x52 || $_byte2 == 0x51 || $_byte2 == 0x57 || $_byte2 == 0x50) + set $_nextaddress = $pc + 0x3 + end + # call *0x????????(%ebx) (0xFF93????????) || + if ($_byte2 == 0x93 || $_byte2 == 0x94 || $_byte2 == 0x90 || $_byte2 == 0x92 || $_byte2 == 0x95 || $_byte2 == 0x15) + set $_nextaddress = $pc + 6 + end + # call *0x????????(%ebx,%eax,4) (0xFF94??????????) + if ($_byte2 == 0x94) + set $_nextaddress = $pc + 7 + end + end + # FIXME: still missing a few? + if ($_byte1 == 0x41 || $_byte1 == 0x40) + if ($_byte2 == 0xFF) + if ($_byte3 == 0xD0 || $_byte3 == 0xD1 || $_byte3 == 0xD2 || $_byte3 == 0xD3 || $_byte3 == 0xD4 || $_byte3 == 0xD5 || $_byte3 == 0xD6 || $_byte3 == 0xD7) + set $_nextaddress = $pc + 0x3 + end + end + end + end + # if we have found a call to bypass we set a temporary breakpoint on next instruction and continue + if ($_nextaddress != 0) + if ($arg0 == 1) + thbreak *$_nextaddress + else + tbreak *$_nextaddress + end + continue + # else we just single step + else + nexti + end + end +end +document stepoframework +Syntax: stepoframework +| Auxiliary function to stepo command. +end + +define stepo + stepoframework 0 +end +document stepo +Syntax: stepo +| Step over calls (interesting to bypass the ones to msgSend). +| This function will set a temporary breakpoint on next instruction after the call so the call will be bypassed. +| You can safely use it instead nexti or n since it will single step code if it's not a call instruction (unless you want to go into the call function). +end + + +define stepoh + stepoframework 1 +end +document stepoh +Syntax: stepoh +| Same as stepo command but uses temporary hardware breakpoints. +end + + +# FIXME: ARM +define skip + x/2i $pc + set $instruction_size = (int)($_ - $pc) + set $pc = $pc + $instruction_size + if ($SKIPEXECUTE == 1) + if ($SKIPSTEP == 1) + stepo + else + stepi + end + else + context + end +end +document skip +Syntax: skip +| Skip over the instruction located at EIP/RIP. By default, the instruction will not be executed! +| Some configurable options are available on top of gdbinit to override this. +end + + +# _______________eflags commands______________ +# conditional flags are +# negative/less than (N), bit 31 of CPSR +# zero (Z), bit 30 +# Carry/Borrow/Extend (C), bit 29 +# Overflow (V), bit 28 + +# negative/less than (N), bit 31 of CPSR +define cfn + if $ARM == 1 + set $tempflag = $cpsr->n + if ($tempflag & 1) + set $cpsr->n = $tempflag&~0x1 + else + set $cpsr->n = $tempflag|0x1 + end + end +end +document cfn +Syntax: cfn +| Change Negative/Less Than Flag. +end + + +define cfc +# Carry/Borrow/Extend (C), bit 29 + if $ARM == 1 + set $tempflag = $cpsr->c + if ($tempflag & 1) + set $cpsr->c = $tempflag&~0x1 + else + set $cpsr->c = $tempflag|0x1 + end + else + if ((unsigned int)$eflags & 1) + set $eflags = (unsigned int)$eflags&~0x1 + else + set $eflags = (unsigned int)$eflags|0x1 + end + end +end +document cfc +Syntax: cfc +| Change Carry Flag. +end + + +define cfp + if (((unsigned int)$eflags >> 2) & 1) + set $eflags = (unsigned int)$eflags&~0x4 + else + set $eflags = (unsigned int)$eflags|0x4 + end +end +document cfp +Syntax: cfp +| Change Parity Flag. +end + + +define cfa + if (((unsigned int)$eflags >> 4) & 1) + set $eflags = (unsigned int)$eflags&~0x10 + else + set $eflags = (unsigned int)$eflags|0x10 + end +end +document cfa +Syntax: cfa +| Change Auxiliary Carry Flag. +end + + +define cfz +# zero (Z), bit 30 + if $ARM == 1 + set $tempflag = $cpsr->z + if ($tempflag & 1) + set $cpsr->z = $tempflag&~0x1 + else + set $cpsr->z = $tempflag|0x1 + end + else + if (((unsigned int)$eflags >> 6) & 1) + set $eflags = (unsigned int)$eflags&~0x40 + else + set $eflags = (unsigned int)$eflags|0x40 + end + end +end +document cfz +Syntax: cfz +| Change Zero Flag. +end + + +define cfs + if (((unsigned int)$eflags >> 7) & 1) + set $eflags = (unsigned int)$eflags&~0x80 + else + set $eflags = (unsigned int)$eflags|0x80 + end +end +document cfs +Syntax: cfs +| Change Sign Flag. +end + + +define cft + if (((unsigned int)$eflags >>8) & 1) + set $eflags = (unsigned int)$eflags&~0x100 + else + set $eflags = (unsigned int)$eflags|0x100 + end +end +document cft +Syntax: cft +| Change Trap Flag. +end + + +define cfi + if (((unsigned int)$eflags >> 9) & 1) + set $eflags = (unsigned int)$eflags&~0x200 + else + set $eflags = (unsigned int)$eflags|0x200 + end +end +document cfi +Syntax: cfi +| Change Interrupt Flag. +| Only privileged applications (usually the OS kernel) may modify IF. +| This only applies to protected mode (real mode code may always modify IF). +end + + +define cfd + if (((unsigned int)$eflags >>0xA) & 1) + set $eflags = (unsigned int)$eflags&~0x400 + else + set $eflags = (unsigned int)$eflags|0x400 + end +end +document cfd +Syntax: cfd +| Change Direction Flag. +end + + +define cfo + if (((unsigned int)$eflags >> 0xB) & 1) + set $eflags = (unsigned int)$eflags&~0x800 + else + set $eflags = (unsigned int)$eflags|0x800 + end +end +document cfo +Syntax: cfo +| Change Overflow Flag. +end + + +# Overflow (V), bit 28 +define cfv + if $ARM == 1 + set $tempflag = $cpsr->v + if ($tempflag & 1) + set $cpsr->v = $tempflag&~0x1 + else + set $cpsr->v = $tempflag|0x1 + end + end +end +document cfv +Syntax: cfv +| Change Overflow Flag. +end + + +# ____________________patch___________________ +# the usual nops are mov r0,r0 for arm (0xe1a00000) +# and mov r8,r8 in Thumb (0x46c0) +# armv7 has other nops +# FIXME: make sure that the interval fits the 32bits address for arm and 16bits for thumb +# status: works, fixme +define nop + if ($argc > 2 || $argc == 0) + help nop + end + + if $ARM == 1 + if ($argc == 1) + if ($cpsr->t &1) + # thumb + set *(short *)$arg0 = 0x46c0 + else + # arm + set *(int *)$arg0 = 0xe1a00000 + end + else + set $addr = $arg0 + if ($cpsr->t & 1) + # thumb + while ($addr < $arg1) + set *(short *)$addr = 0x46c0 + set $addr = $addr + 2 + end + else + # arm + while ($addr < $arg1) + set *(int *)$addr = 0xe1a00000 + set $addr = $addr + 4 + end + end + end + else + if ($argc == 1) + set *(unsigned char *)$arg0 = 0x90 + else + set $addr = $arg0 + while ($addr < $arg1) + set *(unsigned char *)$addr = 0x90 + set $addr = $addr + 1 + end + end + end +end +document nop +Syntax: nop ADDR1 [ADDR2] +| Patch a single byte at address ADDR1, or a series of bytes between ADDR1 and ADDR2 to a NOP (0x90) instruction. +| ARM or Thumb code will be patched accordingly. +end + + +define null + if ( $argc >2 || $argc == 0) + help null + end + + if ($argc == 1) + set *(unsigned char *)$arg0 = 0 + else + set $addr = $arg0 + while ($addr < $arg1) + set *(unsigned char *)$addr = 0 + set $addr = $addr +1 + end + end +end +document null +Syntax: null ADDR1 [ADDR2] +| Patch a single byte at address ADDR1 to NULL (0x00), or a series of bytes between ADDR1 and ADDR2. +end + +# FIXME: thumb breakpoint ? +define int3 + if $argc != 1 + help int3 + else + if $ARM == 1 + set $ORIGINAL_INT3 = *(unsigned int *)$arg0 + set $ORIGINAL_INT3ADDRESS = $arg0 + set *(unsigned int*)$arg0 = 0xe7ffdefe + else + # save original bytes and address + set $ORIGINAL_INT3 = *(unsigned char *)$arg0 + set $ORIGINAL_INT3ADDRESS = $arg0 + # patch + set *(unsigned char *)$arg0 = 0xCC + end + end +end +document int3 +Syntax int3 ADDR +| Patch byte at address ADDR to an INT3 (0xCC) instruction or the equivalent software breakpoint for ARM. +end + + +define rint3 + if $ARM == 1 + set *(unsigned int *)$ORIGINAL_INT3ADDRESS = $ORIGINAL_INT3 + set $pc = $ORIGINAL_INT3ADDRESS + else + set *(unsigned char *)$ORIGINAL_INT3ADDRESS = $ORIGINAL_INT3 + if ($64BITS == 1) + set $rip = $ORIGINAL_INT3ADDRESS + else + set $eip = $ORIGINAL_INT3ADDRESS + end + end +end +document rint3 +Syntax: rint3 +| Restore the original byte previous to int3 patch issued with "int3" command. +end + +define patch + if $argc != 3 + help patch + end + set $patchaddr = $arg0 + set $patchbytes = $arg1 + set $patchsize = $arg2 + + if ($patchsize == 1) + set *(unsigned char*)$patchaddr = $patchbytes + end + if ($patchsize == 2) + set $lendianbytes = (unsigned short)(($patchbytes << 8) | ($patchbytes >> 8)) + set *(unsigned short*)$patchaddr = $lendianbytes + end + if ($patchsize == 4) + set $lendianbytes = (unsigned int)( (($patchbytes << 8) & 0xFF00FF00 ) | (($patchbytes >> 8) & 0xFF00FF )) + set $lendianbytes = (unsigned int)($lendianbytes << 0x10 | $lendianbytes >> 0x10) + set *(unsigned int*)$patchaddr = $lendianbytes + end + if ($patchsize == 8) + set $lendianbytes = (unsigned long long)( (($patchbytes << 8) & 0xFF00FF00FF00FF00ULL ) | (($patchbytes >> 8) & 0x00FF00FF00FF00FFULL ) ) + set $lendianbytes = (unsigned long long)( (($lendianbytes << 0x10) & 0xFFFF0000FFFF0000ULL ) | (($lendianbytes >> 0x10) & 0x0000FFFF0000FFFFULL ) ) + set $lendianbytes = (unsigned long long)( ($lendianbytes << 0x20) | ($lendianbytes >> 0x20) ) + set *(unsigned long long*)$patchaddr = $lendianbytes + end +end +document patch +Syntax: patch address bytes size +| Patch a given address, converting the bytes to little-endian. +| Assumes input bytes are unsigned values and should be in hexadecimal format (0x...). +| Size must be 1, 2, 4, 8 bytes. +| Main purpose is to be used with the output from the asm commands. +end + +# ____________________cflow___________________ +define print_insn_type + if $argc != 1 + help print_insn_type + else + if ($arg0 < 0 || $arg0 > 5) + printf "UNDEFINED/WRONG VALUE" + end + if ($arg0 == 0) + printf "UNKNOWN" + end + if ($arg0 == 1) + printf "JMP" + end + if ($arg0 == 2) + printf "JCC" + end + if ($arg0 == 3) + printf "CALL" + end + if ($arg0 == 4) + printf "RET" + end + if ($arg0 == 5) + printf "INT" + end + end +end +document print_insn_type +Syntax: print_insn_type INSN_TYPE_NUMBER +| Print human-readable mnemonic for the instruction type (usually $INSN_TYPE). +end + + +define get_insn_type + if $argc != 1 + help get_insn_type + else + set $INSN_TYPE = 0 + set $_byte1 = *(unsigned char *)$arg0 + if ($_byte1 == 0x9A || $_byte1 == 0xE8) + # "call" + set $INSN_TYPE = 3 + end + if ($_byte1 >= 0xE9 && $_byte1 <= 0xEB) + # "jmp" + set $INSN_TYPE = 1 + end + if ($_byte1 >= 0x70 && $_byte1 <= 0x7F) + # "jcc" + set $INSN_TYPE = 2 + end + if ($_byte1 >= 0xE0 && $_byte1 <= 0xE3 ) + # "jcc" + set $INSN_TYPE = 2 + end + if ($_byte1 == 0xC2 || $_byte1 == 0xC3 || $_byte1 == 0xCA || \ + $_byte1 == 0xCB || $_byte1 == 0xCF) + # "ret" + set $INSN_TYPE = 4 + end + if ($_byte1 >= 0xCC && $_byte1 <= 0xCE) + # "int" + set $INSN_TYPE = 5 + end + if ($_byte1 == 0x0F ) + # two-byte opcode + set $_byte2 = *(unsigned char *)($arg0 + 1) + if ($_byte2 >= 0x80 && $_byte2 <= 0x8F) + # "jcc" + set $INSN_TYPE = 2 + end + end + if ($_byte1 == 0xFF) + # opcode extension + set $_byte2 = *(unsigned char *)($arg0 + 1) + set $_opext = ($_byte2 & 0x38) + if ($_opext == 0x10 || $_opext == 0x18) + # "call" + set $INSN_TYPE = 3 + end + if ($_opext == 0x20 || $_opext == 0x28) + # "jmp" + set $INSN_TYPE = 1 + end + end + end +end +document get_insn_type +Syntax: get_insn_type ADDR +| Recognize instruction type at address ADDR. +| Take address ADDR and set the global $INSN_TYPE variable to +| 0, 1, 2, 3, 4, 5 if the instruction at that address is +| unknown, a jump, a conditional jump, a call, a return, or an interrupt. +end + + +define step_to_call + set $_saved_ctx = $SHOW_CONTEXT + set $SHOW_CONTEXT = 0 + set $SHOW_NEST_INSN = 0 + + set logging file /dev/null + set logging redirect on + set logging on + + set $_cont = 1 + while ($_cont > 0) + stepi + get_insn_type $pc + if ($INSN_TYPE == 3) + set $_cont = 0 + end + end + + set logging off + + if ($_saved_ctx > 0) + context + end + + set $SHOW_CONTEXT = $_saved_ctx + set $SHOW_NEST_INSN = 0 + + set logging file ~/gdb.txt + set logging redirect off + set logging on + + printf "step_to_call command stopped at:\n " + x/i $pc + printf "\n" + set logging off + +end +document step_to_call +Syntax: step_to_call +| Single step until a call instruction is found. +| Stop before the call is taken. +| Log is written into the file ~/gdb.txt. +end + + +define trace_calls + + printf "Tracing...please wait...\n" + + set $_saved_ctx = $SHOW_CONTEXT + set $SHOW_CONTEXT = 0 + set $SHOW_NEST_INSN = 0 + set $_nest = 1 + set listsize 0 + + set logging overwrite on + set logging file ~/gdb_trace_calls.txt + set logging on + set logging off + set logging overwrite off + + while ($_nest > 0) + get_insn_type $pc + # handle nesting + if ($INSN_TYPE == 3) + set $_nest = $_nest + 1 + else + if ($INSN_TYPE == 4) + set $_nest = $_nest - 1 + end + end + # if a call, print it + if ($INSN_TYPE == 3) + set logging file ~/gdb_trace_calls.txt + set logging redirect off + set logging on + + set $x = $_nest - 2 + while ($x > 0) + printf "\t" + set $x = $x - 1 + end + x/i $pc + end + + set logging off + set logging file /dev/null + set logging redirect on + set logging on + stepi + set logging redirect off + set logging off + end + + set $SHOW_CONTEXT = $_saved_ctx + set $SHOW_NEST_INSN = 0 + + printf "Done, check ~/gdb_trace_calls.txt\n" +end +document trace_calls +Syntax: trace_calls +| Create a runtime trace of the calls made by target. +| Log overwrites(!) the file ~/gdb_trace_calls.txt. +end + + +define trace_run + + printf "Tracing...please wait...\n" + + set $_saved_ctx = $SHOW_CONTEXT + set $SHOW_CONTEXT = 0 + set $SHOW_NEST_INSN = 1 + set logging overwrite on + set logging file ~/gdb_trace_run.txt + set logging redirect on + set logging on + set $_nest = 1 + + while ( $_nest > 0 ) + + get_insn_type $pc + # jmp, jcc, or cll + if ($INSN_TYPE == 3) + set $_nest = $_nest + 1 + else + # ret + if ($INSN_TYPE == 4) + set $_nest = $_nest - 1 + end + end + stepi + end + + printf "\n" + + set $SHOW_CONTEXT = $_saved_ctx + set $SHOW_NEST_INSN = 0 + set logging redirect off + set logging off + + # clean up trace file + shell grep -v ' at ' ~/gdb_trace_run.txt > ~/gdb_trace_run.1 + shell grep -v ' in ' ~/gdb_trace_run.1 > ~/gdb_trace_run.txt + shell rm -f ~/gdb_trace_run.1 + printf "Done, check ~/gdb_trace_run.txt\n" +end +document trace_run +Syntax: trace_run +| Create a runtime trace of target. +| Log overwrites(!) the file ~/gdb_trace_run.txt. +end + +define entry_point + + set logging redirect on + set logging file /tmp/gdb-entry_point + set logging on + + info files + + set logging off + + shell entry_point="$(/usr/bin/grep 'Entry point:' /tmp/gdb-entry_point | /usr/bin/awk '{ print $3 }')"; echo "$entry_point"; echo 'set $entry_point_address = '"$entry_point" > /tmp/gdb-entry_point + source /tmp/gdb-entry_point + shell /bin/rm -f /tmp/gdb-entry_point +end +document entry_point +Syntax: entry_point +| Prints the entry point address of the target and stores it in the variable entry_point. +end + +define break_entrypoint + entry_point + break *$entry_point_address +end +document break_entrypoint +Syntax: break_entrypoint +| Sets a breakpoint on the entry point of the target. +end + +define objc_symbols + + set logging redirect on + set logging file /tmp/gdb-objc_symbols + set logging on + + info target + + set logging off + # XXX: define paths for objc-symbols and SymTabCreator + shell target="$(/usr/bin/head -1 /tmp/gdb-objc_symbols | /usr/bin/head -1 | /usr/bin/awk -F '"' '{ print $2 }')"; objc-symbols "$target" | SymTabCreator -o /tmp/gdb-symtab + + set logging on + add-symbol-file /tmp/gdb-symtab + set logging off + shell /bin/rm -f /tmp/gdb-objc_symbols +end +document objc_symbols +Syntax: objc_symbols +| Loads stripped objc symbols into gdb using objc-symbols and SymTabCreator +| See http://stackoverflow.com/questions/17554070/import-class-dump-info-into-gdb +| and https://github.com/0xced/class-dump/tree/objc-symbols (for the required utils) +end + +#define ptraceme +# catch syscall ptrace +# commands +# if ($64BITS == 0) +# if ($ebx == 0) +# set $eax = 0 +# continue +# end +# else +# if ($rdi == 0) +# set $rax = 0 +# continue +# end +# end +# end +# set $ptrace_bpnum = $bpnum +#end +#document ptraceme +#Syntax: ptraceme +#| Hook ptrace to bypass PTRACE_TRACEME anti debugging technique +#end + +define rptraceme + if ($ptrace_bpnum != 0) + delete $ptrace_bpnum + set $ptrace_bpnum = 0 + end +end +document rptraceme +Syntax: rptraceme +| Remove ptrace hook. +end + + +# ____________________misc____________________ +define hook-stop + if (sizeof(void*) == 8) + set $64BITS = 1 + else + set $64BITS = 0 + end + + if ($KDP64BITS != -1) + if ($KDP64BITS == 0) + set $64BITS = 0 + else + set $64BITS = 1 + end + end + + # Display instructions formats + if $ARM == 1 + if $ARMOPCODES == 1 + set arm show-opcode-bytes 1 + end + else + if $X86FLAVOR == 0 + set disassembly-flavor intel + else + set disassembly-flavor att + end + end + + # this makes 'context' be called at every BP/step + if ($SHOW_CONTEXT > 0) + context + end + if ($SHOW_NEST_INSN > 0) + set $x = $_nest + while ($x > 0) + printf "\t" + set $x = $x - 1 + end + end +end +document hook-stop +Syntax: hook-stop +| !!! FOR INTERNAL USE ONLY - DO NOT CALL !!! +end + + +# original by Tavis Ormandy (http://my.opera.com/taviso/blog/index.dml/tag/gdb) (great fix!) +# modified to work with Mac OS X by fG! +# seems nasm shipping with Mac OS X has problems accepting input from stdin or heredoc +# input is read into a variable and sent to a temporary file which nasm can read +define assemble + # dont enter routine again if user hits enter + dont-repeat + if ($argc) + if (*$arg0 = *$arg0) + # check if we have a valid address by dereferencing it, + # if we havnt, this will cause the routine to exit. + end + printf "Instructions will be written to %#x.\n", $arg0 + else + printf "Instructions will be written to stdout.\n" + end + printf "Type instructions, one per line." + color_bold + printf " Do not forget to use NASM assembler syntax!\n" + color_reset + printf "End with a line saying just \"end\".\n" + + if ($argc) + if ($64BITS == 1) + # argument specified, assemble instructions into memory at address specified. + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 64\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/local/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/bin/hexdump -ve '1/1 "set *((unsigned char *) $arg0 + %#2_ax) = %#02x\n"' >/tmp/gdbassemble ; /bin/rm -f /tmp/$GDBASMFILENAME + source /tmp/gdbassemble + # all done. clean the temporary file + shell /bin/rm -f /tmp/gdbassemble + else + # argument specified, assemble instructions into memory at address specified. + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 32\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/bin/hexdump -ve '1/1 "set *((unsigned char *) $arg0 + %#2_ax) = %#02x\n"' >/tmp/gdbassemble ; /bin/rm -f /tmp/$GDBASMFILENAME + source /tmp/gdbassemble + # all done. clean the temporary file + shell /bin/rm -f /tmp/gdbassemble + end + else + if ($64BITS == 1) + # no argument, assemble instructions to stdout + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 64\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/local/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/local/bin/ndisasm -i -b64 /dev/stdin ; \ + /bin/rm -f /tmp/$GDBASMFILENAME + else + # no argument, assemble instructions to stdout + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 32\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/bin/ndisasm -i -b32 /dev/stdin ; \ + /bin/rm -f /tmp/$GDBASMFILENAME + end + end +end +document assemble +Syntax: assemble +| Assemble instructions using nasm. +| Type a line containing "end" to indicate the end. +| If an address is specified, insert/modify instructions at that address. +| If no address is specified, assembled instructions are printed to stdout. +| Use the pseudo instruction "org ADDR" to set the base address. +end + +define assemble32 + # dont enter routine again if user hits enter + dont-repeat + if ($argc) + if (*$arg0 = *$arg0) + # check if we have a valid address by dereferencing it, + # if we havnt, this will cause the routine to exit. + end + printf "Instructions will be written to %#x.\n", $arg0 + else + printf "Instructions will be written to stdout.\n" + end + printf "Type instructions, one per line." + color_bold + printf " Do not forget to use NASM assembler syntax!\n" + color_reset + printf "End with a line saying just \"end\".\n" + + if ($argc) + # argument specified, assemble instructions into memory at address specified. + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 32\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/bin/hexdump -ve '1/1 "set *((unsigned char *) $arg0 + %#2_ax) = %#02x\n"' >/tmp/gdbassemble ; /bin/rm -f /tmp/$GDBASMFILENAME + source /tmp/gdbassemble + # all done. clean the temporary file + shell /bin/rm -f /tmp/gdbassemble + else + # no argument, assemble instructions to stdout + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 32\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/bin/ndisasm -i -b32 /dev/stdin ; \ + /bin/rm -f /tmp/$GDBASMFILENAME + end +end +document assemble32 +Syntax: assemble32 +| Assemble 32 bits instructions using nasm. +| Type a line containing "end" to indicate the end. +| If an address is specified, insert/modify instructions at that address. +| If no address is specified, assembled instructions are printed to stdout. +| Use the pseudo instruction "org ADDR" to set the base address. +end + +define assemble64 + # dont enter routine again if user hits enter + dont-repeat + if ($argc) + if (*$arg0 = *$arg0) + # check if we have a valid address by dereferencing it, + # if we havnt, this will cause the routine to exit. + end + printf "Instructions will be written to %#x.\n", $arg0 + else + printf "Instructions will be written to stdout.\n" + end + printf "Type instructions, one per line." + color_bold + printf " Do not forget to use NASM assembler syntax!\n" + color_reset + printf "End with a line saying just \"end\".\n" + + if ($argc) + # argument specified, assemble instructions into memory at address specified. + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 64\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/local/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/bin/hexdump -ve '1/1 "set *((unsigned char *) $arg0 + %#2_ax) = %#02x\n"' >/tmp/gdbassemble ; /bin/rm -f /tmp/$GDBASMFILENAME + source /tmp/gdbassemble + # all done. clean the temporary file + shell /bin/rm -f /tmp/gdbassemble + else + # no argument, assemble instructions to stdout + shell ASMOPCODE="$(while read -ep '>' r && test "$r" != end ; do echo -E "$r"; done)" ; GDBASMFILENAME=$RANDOM; \ + echo -e "BITS 64\n$ASMOPCODE" >/tmp/$GDBASMFILENAME ; /usr/local/bin/nasm -f bin -o /dev/stdout /tmp/$GDBASMFILENAME | /usr/local/bin/ndisasm -i -b64 /dev/stdin ; \ + /bin/rm -f /tmp/$GDBASMFILENAME + end +end +document assemble64 +Syntax: assemble64 +| Assemble 64 bits instructions using nasm. +| Type a line containing "end" to indicate the end. +| If an address is specified, insert/modify instructions at that address. +| If no address is specified, assembled instructions are printed to stdout. +| Use the pseudo instruction "org ADDR" to set the base address. +end + +define asm + if $argc == 1 + assemble $arg0 + else + assemble + end +end +document asm +Syntax: asm +| Shortcut to the asssemble command. +end + +define asm32 + if $argc == 1 + assemble32 $arg0 + else + assemble32 + end +end +document asm32 +Syntax: asm32 +| Shortcut to the assemble32 command. +end + +define asm64 + if $argc == 1 + assemble64 $arg0 + else + assemble64 + end +end +document asm64 +Syntax: asm64 +| Shortcut to the assemble64 command. +end + +define assemble_gas + printf "\nType code to assemble and hit Ctrl-D when finished.\n" + printf "You must use GNU assembler (AT&T) syntax.\n" + + shell filename=$(mktemp); \ + binfilename=$(mktemp); \ + echo -e "Writing into: ${filename}\n"; \ + cat > $filename; echo ""; \ + as -o $binfilename < $filename; \ + objdump -d -j .text $binfilename; \ + rm -f $binfilename; \ + rm -f $filename; \ + echo -e "temporaly files deleted.\n" +end +document assemble_gas +Syntax: assemble_gas +| Assemble instructions to binary opcodes. Uses GNU as and objdump. +end + + +define dump_hexfile + dump ihex memory $arg0 $arg1 $arg2 +end +document dump_hexfile +Syntax: dump_hexfile FILENAME ADDR1 ADDR2 +| Write a range of memory to a file in Intel ihex (hexdump) format. +| The range is specified by ADDR1 and ADDR2 addresses. +end + + +define dump_binfile + dump memory $arg0 $arg1 $arg2 +end +document dump_binfile +Syntax: dump_binfile FILENAME ADDR1 ADDR2 +| Write a range of memory to a binary file. +| The range is specified by ADDR1 and ADDR2 addresses. +end + + +define dumpmacho + if $argc != 2 + help dumpmacho + end + set $headermagic = *$arg0 + # the || operator isn't working as it should, wtf!!! + if $headermagic != 0xfeedface + if $headermagic != 0xfeedfacf + printf "[Error] Target address doesn't contain a valid Mach-O binary!\n" + help dumpmacho + end + end + set $headerdumpsize = *($arg0+0x14) + if $headermagic == 0xfeedface + dump memory $arg1 $arg0 ($arg0+0x1c+$headerdumpsize) + end + if $headermagic == 0xfeedfacf + dump memory $arg1 $arg0 ($arg0+0x20+$headerdumpsize) + end +end +document dumpmacho +Syntax: dumpmacho STARTADDRESS FILENAME +| Dump the Mach-O header to a file. +| You need to input the start address (use info shared command to find it). +end + + +define cls + shell clear +end +document cls +Syntax: cls +| Clear screen. +end + + +define search + set $start = (char *) $arg0 + set $end = (char *) $arg1 + set $pattern = (short) $arg2 + set $p = $start + while $p < $end + if (*(short *) $p) == $pattern + printf "pattern 0x%hx found at 0x%x\n", $pattern, $p + end + set $p++ + end +end +document search +Syntax: search +| Search for the given pattern beetween $start and $end address. +end + + +# _________________user tips_________________ +# The 'tips' command is used to provide tutorial-like info to the user +define tips + printf "Tip Topic Commands:\n" + printf "\ttip_display : Automatically display values on each break\n" + printf "\ttip_patch : Patching binaries\n" + printf "\ttip_strip : Dealing with stripped binaries\n" + printf "\ttip_syntax : AT&T vs Intel syntax\n" +end +document tips +Syntax: tips +| Provide a list of tips from users on various topics. +end + + +define tip_patch + printf "\n" + printf " PATCHING MEMORY\n" + printf "Any address can be patched using the 'set' command:\n" + printf "\t`set ADDR = VALUE` \te.g. `set *0x8049D6E = 0x90`\n" + printf "\n" + printf " PATCHING BINARY FILES\n" + printf "Use `set write` in order to patch the target executable\n" + printf "directly, instead of just patching memory\n" + printf "\t`set write on` \t`set write off`\n" + printf "Note that this means any patches to the code or data segments\n" + printf "will be written to the executable file\n" + printf "When either of these commands has been issued,\n" + printf "the file must be reloaded.\n" + printf "\n" +end +document tip_patch +Syntax: tip_patch +| Tips on patching memory and binary files. +end + + +define tip_strip + printf "\n" + printf " STOPPING BINARIES AT ENTRY POINT\n" + printf "Stripped binaries have no symbols, and are therefore tough to\n" + printf "start automatically. To debug a stripped binary, use\n" + printf "\tinfo file\n" + printf "to get the entry point of the file\n" + printf "The first few lines of output will look like this:\n" + printf "\tSymbols from '/tmp/a.out'\n" + printf "\tLocal exec file:\n" + printf "\t `/tmp/a.out', file type elf32-i386.\n" + printf "\t Entry point: 0x80482e0\n" + printf "Use this entry point to set an entry point:\n" + printf "\t`tbreak *0x80482e0`\n" + printf "The breakpoint will delete itself after the program stops as\n" + printf "the entry point\n" + printf "\n" +end +document tip_strip +Syntax: tip_strip +| Tips on dealing with stripped binaries. +end + + +define tip_syntax + printf "\n" + printf "\t INTEL SYNTAX AT&T SYNTAX\n" + printf "\tmnemonic dest, src, imm mnemonic src, dest, imm\n" + printf "\t[base+index*scale+disp] disp(base, index, scale)\n" + printf "\tregister: eax register: %%eax\n" + printf "\timmediate: 0xFF immediate: $0xFF\n" + printf "\tdereference: [addr] dereference: addr(,1)\n" + printf "\tabsolute addr: addr absolute addr: *addr\n" + printf "\tbyte insn: mov byte ptr byte insn: movb\n" + printf "\tword insn: mov word ptr word insn: movw\n" + printf "\tdword insn: mov dword ptr dword insn: movd\n" + printf "\tfar call: call far far call: lcall\n" + printf "\tfar jump: jmp far far jump: ljmp\n" + printf "\n" + printf "Note that order of operands in reversed, and that AT&T syntax\n" + printf "requires that all instructions referencing memory operands \n" + printf "use an operand size suffix (b, w, d, q)\n" + printf "\n" +end +document tip_syntax +Syntax: tip_syntax +| Summary of Intel and AT&T syntax differences. +end + + +define tip_display + printf "\n" + printf "Any expression can be set to automatically be displayed every time\n" + printf "the target stops. The commands for this are:\n" + printf "\t`display expr' : automatically display expression 'expr'\n" + printf "\t`display' : show all displayed expressions\n" + printf "\t`undisplay num' : turn off autodisplay for expression # 'num'\n" + printf "Examples:\n" + printf "\t`display/x *(int *)$esp` : print top of stack\n" + printf "\t`display/x *(int *)($ebp+8)` : print first parameter\n" + printf "\t`display (char *)$esi` : print source string\n" + printf "\t`display (char *)$edi` : print destination string\n" + printf "\n" +end +document tip_display +Syntax: tip_display +| Tips on automatically displaying values when a program stops. +end + +# bunch of semi-useless commands + +# enable and disable shortcuts for stop-on-solib-events fantastic trick! +define enablesolib + set stop-on-solib-events 1 + printf "Stop-on-solib-events is enabled!\n" +end +document enablesolib +Syntax: enablesolib +| Shortcut to enable stop-on-solib-events trick. +end + + +define disablesolib + set stop-on-solib-events 0 + printf "Stop-on-solib-events is disabled!\n" +end +document disablesolib +Syntax: disablesolib +| Shortcut to disable stop-on-solib-events trick. +end + + +# enable commands for different displays +define enabledisasm + set $SHOWDISASM = 1 +end +document enabledisasm +Syntax: enabledisasm +| Enable disassembly display. +end + +define enableobjectivec + set $SHOWOBJECTIVEC = 1 +end +document enableobjectivec +Syntax: enableobjectivec +| Enable display of objective-c information in the context window. +end + + +define enablecpuregisters + set $SHOWCPUREGISTERS = 1 +end +document enablecpuregisters +Syntax: enablecpuregisters +| Enable display of cpu registers in the context window. +end + + +define enablestack + set $SHOWSTACK = 1 +end +document enablestack +Syntax: enablestack +| Enable display of stack in the context window. +end + + +define enabledatawin + set $SHOWDATAWIN = 1 +end +document enabledatawin +Syntax: enabledatawin +| Enable display of data window in the context window. +end + + +# disable commands for different displays +define disabledisasm + set $SHOWDISASM = 0 +end +document disabledisasm +Syntax: disabledisasm +| Disable disassembly display. +end + +define disableobjectivec + set $SHOWOBJECTIVEC = 0 +end +document disableobjectivec +Syntax: disableobjectivec +| Disable display of objective-c information in the context window. +end + + +define disablecpuregisters + set $SHOWCPUREGISTERS = 0 +end +document disablecpuregisters +Syntax: disablecpuregisters +| Disable display of cpu registers in the context window. +end + + +define disablestack + set $SHOWSTACK = 0 +end +document disablestack +Syntax: disablestack +| Disable display of stack information in the context window. +end + + +define disabledatawin + set $SHOWDATAWIN = 0 +end +document disabledatawin +Syntax: disabledatawin +| Disable display of data window in the context window. +end + + +define arm + if $ARMOPCODES == 1 + set arm show-opcode-bytes 1 + end + set $ARM = 1 +end +document arm +Syntax: arm +| Set gdb to work with ARM binaries. +end + +define ioskdp + set $SHOW_CONTEXT = 0 + set $SHOW_NEST_INSN = 0 +end +document ioskdp +Syntax: ioskdp +| Disable dumping context information for iOS KDP debugging +end + +define intelsyntax + if $ARM == 0 + set disassembly-flavor intel + set $X86FLAVOR = 0 + end +end +document intelsyntax +Syntax: intelsyntax +| Change disassembly syntax to intel flavor. +end + + +define attsyntax + if $ARM == 0 + set disassembly-flavor att + set $X86FLAVOR = 1 + end +end +document attsyntax +Syntax: attsyntax +| Change disassembly syntax to at&t flavor. +end + +define kernel32 + if $argc != 0 + # try to load kgmacros files + # failure is silent if non-existent... + source $arg0 + set architecture i386 + if $argc == 2 + target remote localhost:$arg1 + else + target remote localhost:8832 + end + else + help kernel32 + end +end +document kernel32 +Syntax: kernel32 PATH_TO_KGMACROS +| Attach to VMware gdb stub for 32 bits kernel. +| The path to kgmacros must be supplied as first parameter. +| If you don't want to load kgmacros just put something as the first parameter. +| Optional parameter is the port to connect to, in case you are not using the default 8832 +| or want to kernel debug more than one active virtual machine. +| By supplying a bogus kgmacros this command should be compatible with any OS. +end + +define kernel64 + if $argc != 0 + # try to load kgmacros files + # failure is silent if non-existent... + source $arg0 + set architecture i386:x86-64 + if $argc == 2 + target remote localhost:$arg1 + else + target remote localhost:8864 + end + else + help kernel64 + end +end +document kernel64 +Syntax: kernel64 PATH_TO_KGMACROS +| Attach to VMware gdb stub for 64 bits kernel. +| The path to kgmacros must be supplied as first parameter. +| If you don't want to load kgmacros just put something as the first parameter. +| Optional parameter is the port to connect to, in case you are not using the default 8864 +| or want to kernel debug more than one active virtual machine. +| By supplying a bogus kgmacros this command should be compatible with any OS. +end + +define 32bits + set $KDP64BITS = 0 + set $64BITS = 0 +end + +define 64bits + set $KDP64BITS = 1 + set $64BITS = 1 +end + +define resetkdp + set $KDP64BITS = -1 +end + +define header + if $argc != 1 + help header + else + dump memory /tmp/gdbinit_header_dump $arg0 $arg0 + 4096 + shell /usr/bin/otool -h /tmp/gdbinit_header_dump + shell /bin/rm -f /tmp/gdbinit_header_dump + end +end +document header +Syntax: header MACHO_HEADER_START_ADDRESS +| Dump the Mach-O header located at given address +end + +define loadcmds + if $argc != 1 + help loadcmds + else + # this size should be good enough for most binaries + dump memory /tmp/gdbinit_header_dump $arg0 $arg0 + 4096 * 10 + shell /usr/bin/otool -l /tmp/gdbinit_header_dump + shell /bin/rm -f /tmp/gdbinit_header_dump + end +end +document loadcmds +Syntax: loadcmds MACHO_HEADER_START_ADDRESS +| Dump the Mach-O load commands +end + +# defining it here doesn't get the space #$#$%"#! +define disablecolorprompt + set prompt gdb$ +end +document disablecolorprompt +| Remove color from prompt +end + +define enablecolorprompt + set prompt \033[31mgdb$ \033[0m +end +document enablecolorprompt +| Enable color prompt +end + +#EOF + +# Older change logs: +# Version 8.0.6 (05/09/2013) +# - Add patch command to convert bytes to little-endian and patch memory +# +# Version 8.0.5 (18/08/2013) +# - Add commands header and loadcmds to dump Mach-O header information +# - Other fixes and additions from previous commits +# +# Version 8.0.4 (08/05/2013) +# - Detect automatically 32 or 64 bits archs using sizeof(void*). +# Thanks to Tyilo for the simple but very effective idea! +# - Typo in hexdump command also fixed by vuquangtrong. +# - Add shortcuts to attach to VMware kernel debugging gdb stub (kernel32 and kernel64) +# +# Version 8.0.3 (21/03/2013) +# - Add option to colorize or not output (thanks to argp and skier for the request and ideas!) +# - Convert the escape codes into functions so colors can be easily customized +# - Other enhancements available at git commit logs +# Thanks to Plouj, argp, xristos for their ideas and fixes! +# +# Version 8.0.2 (31/07/2012) +# - Merge pull request from mheistermann to support local modifications in a .gdbinit.local file +# - Add a missing opcode to the stepo command +# +# Version 8.0.1 (23/04/2012) +# - Small bug fix to the attsyntax and intelsyntax commands (changing X86 flavor variable was missing) +# +# Version 8.0 (13/04/2012) +# - Merged x86/x64 and ARM versions +# - Added commands intelsyntax and attsyntax to switch between x86 disassembly flavors +# - Added new configuration variables ARM, ARMOPCODES, and X86FLAVOR +# - Code cleanups and fixes to the indentation +# - Bug fixes to some ARM related code +# - Added the dumpmacho command to memory dump the mach-o header to a file +# +# Version 7.4.4 (02/01/2012) +# - Added the "skip" command. This will jump to the next instruction after EIP/RIP without executing the current one. +# Thanks to @bSr43 for the tip to retrieve the current instruction size. +# +# Version 7.4.3 (04/11/2011) +# - Modified "hexdump" command to support a variable number of lines (optional parameter) +# - Removed restrictions on type of addresses in the "dd" command - Thanks to Plouj for the warning :-) +# I don't know what was the original thinking behind those :-) +# - Modified the assemble command to support 64bits - You will need to recompile nasm since the version shipped with OS X doesn't supports 64bits (www.nasm.us). +# Assumes that the new binary is installed at /usr/local/bin - modify the variable at the top if you need so. +# It will assemble based on the target arch being debugged. If you want to use gdb for a quick asm just use the 32bits or 64bits commands to set your target. +# Thanks to snare for the warning and original patch :-) +# - Added "asm" command - it's a shortcut to the "assemble" command. +# - Added configuration variable for colorized prompt. Plouj reported some issues with Ubuntu's gdb 7.2 if prompt is colorized. +# +# Version 7.4.2 (11/08/2011) +# Small fix to a weird bug happening on FreeBSD 8.2. It doesn't like a "if(" instruction, needs to be "if (". Weird! +# Many thanks to Evan for reporting and sending the patch :-) +# Added the ptraceme/rptraceme commands to bypass PTRACE_TRACME anti-debugging technique. +# Grabbed this from http://falken.tuxfamily.org/?p=171 +# It's commented out due to a gdb problem in OS X (refer to http://reverse.put.as/2011/08/20/another-patch-for-apples-gdb-the-definecommands-problem/ ) +# Just uncomment it if you want to use in ptrace enabled systems. +# +# Version 7.4.1 (21/06/2011) - fG! +# Added patch sent by sbz, more than 1 year ago, which I forgot to add :-/ +# This will allow to search for a given pattern between start and end address. +# On sbz words: "It's usefull to find call, ret or everything like that." :-) +# New command is "search" +# +# Version 7.4 (20/06/2011) - fG! +# When registers change between instructions the color will change to red (like it happens in OllyDBG) +# This is the default behavior, if you don't like it, modify the variable SHOWREGCHANGES +# Added patch sent by Philippe Langlois +# color the first disassembly line - change the setting below on SETCOLOR1STLINE - by default it's disabled +# +# Version 7.3.2 (21/02/2011) - fG! +# Added the command rint3 and modified the int3 command. The new command will restore the byte in previous int3 patch. +# +# Version 7.3.1 (29/06/2010) - fG! +# Added enablelib/disablelib command to quickly set the stop-on-solib-events trick +# Implemented the stepoh command equivalent to the stepo but using hardware breakpoints +# More fixes to stepo +# +# Version 7.3 (16/04/2010) - fG! +# Support for 64bits targets. Default is 32bits, you should modify the variable or use the 32bits or 64bits to choose the mode. +# I couldn't find another way to recognize the type of binary… Testing the register doesn't work that well. +# TODO: fix objectivec messages and stepo for 64bits +# Version 7.2.1 (24/11/2009) - fG! +# Another fix to stepo (0xFF92 missing) +# +# Version 7.2 (11/10/2009) - fG! +# Added the smallregisters function to create 16 and 8 bit versions from the registers EAX, EBX, ECX, EDX +# Revised and fixed all the dumpjump stuff, following Intel manuals. There were some errors (thx to rev who pointed the jle problem). +# Small fix to stepo command (missed a few call types) +# +# Version 7.1.7 - fG! +# Added the possibility to modify what's displayed with the context window. You can change default options at the gdb options part. For example, kernel debugging is much slower if the stack display is enabled... +# New commands enableobjectivec, enablecpuregisters, enablestack, enabledatawin and their disable equivalents (to support realtime change of default options) +# Fixed problem with the assemble command. I was calling /bin/echo which doesn't support the -e option ! DUH ! Should have used bash internal version. +# Small fixes to colors... +# New commands enablesolib and disablesolib . Just shortcuts for the stop-on-solib-events fantastic trick ! Hey... I'm lazy ;) +# Fixed this: Possible removal of "u" command, info udot is missing in gdb 6.8-debian . Doesn't exist on OS X so bye bye !!! +# Displays affected flags in jump decisions +# +# Version 7.1.6 - fG! +# Added modified assemble command from Tavis Ormandy (further modified to work with Mac OS X) (shell commands used use full path name, working for Leopard, modify for others if necessary) +# Renamed thread command to threads because thread is an internal gdb command that allows to move between program threads +# +# Version 7.1.5 (04/01/2009) - fG! +# Fixed crash on Leopard ! There was a If Else condition where the else had no code and that made gdb crash on Leopard (CRAZY!!!!) +# Better code indention +# +# Version 7.1.4 (02/01/2009) - fG! +# Bug in show objective c messages with Leopard ??? +# Nop routine support for single address or range (contribution from gln [ghalen at hack.se]) +# Used the same code from nop to null routine +# +# Version 7.1.3 (31/12/2008) - fG! +# Added a new command 'stepo'. This command will step a temporary breakpoint on next instruction after the call, so you can skip over +# the call. Did this because normal commands not always skip over (mainly with objc_msgSend) +# +# Version 7.1.2 (31/12/2008) - fG! +# Support for the jump decision (will display if a conditional jump will be taken or not) +# +# Version 7.1.1 (29/12/2008) - fG! +# Moved gdb options to the beginning (makes more sense) +# Added support to dump message being sent to msgSend (easier to understand what's going on) +# +# Version 7.1 +# Fixed serious (and old) bug in dd and datawin, causing dereference of +# obviously invalid address. See below: +# gdb$ dd 0xffffffff +# FFFFFFFF : Cannot access memory at address 0xffffffff +# +# Version 7.0 +# Added cls command. +# Improved documentation of many commands. +# Removed bp_alloc, was neither portable nor usefull. +# Checking of passed argument(s) in these commands: +# contextsize-stack, contextsize-data, contextsize-code +# bp, bpc, bpe, bpd, bpt, bpm, bhb,... +# Fixed bp and bhb inconsistencies, look at * signs in Version 6.2 +# Bugfix in bhb command, changed "break" to "hb" command body +# Removed $SHOW_CONTEXT=1 from several commands, this variable +# should only be controlled globally with context-on and context-off +# Improved stack, func, var and sig, dis, n, go,... +# they take optional argument(s) now +# Fixed wrong $SHOW_CONTEXT assignment in context-off +# Fixed serious bug in cft command, forgotten ~ sign +# Fixed these bugs in step_to_call: +# 1) the correct logging sequence is: +# set logging file > set logging redirect > set logging on +# 2) $SHOW_CONTEXT is now correctly restored from $_saved_ctx +# Fixed these bugs in trace_calls: +# 1) the correct logging sequence is: +# set logging file > set logging overwrite > +# set logging redirect > set logging on +# 2) removed the "clean up trace file" part, which is not needed now, +# stepi output is properly redirected to /dev/null +# 3) $SHOW_CONTEXT is now correctly restored from $_saved_ctx +# Fixed bug in trace_run: +# 1) $SHOW_CONTEXT is now correctly restored from $_saved_ctx +# Fixed print_insn_type -- removed invalid semicolons!, wrong value checking, +# Added TODO entry regarding the "u" command +# Changed name from gas_assemble to assemble_gas due to consistency +# Output from assemble and assemble_gas is now similar, because i made +# both of them to use objdump, with respect to output format (AT&T|Intel). +# Whole code was checked and made more consistent, readable/maintainable. +# +# Version 6.2 +# Add global variables to allow user to control stack, data and code window sizes +# Increase readability for registers +# Some corrections (hexdump, ddump, context, cfp, assemble, gas_asm, tips, prompt) +# +# Version 6.1-color-user +# Took the Gentoo route and ran sed s/user/user/g +# +# Version 6.1-color +# Added color fixes from +# http://gnurbs.blogsome.com/2006/12/22/colorizing-mamons-gdbinit/ +# +# Version 6.1 +# Fixed filename in step_to_call so it points to /dev/null +# Changed location of logfiles from /tmp to ~ +# +# Version 6 +# Added print_insn_type, get_insn_type, context-on, context-off commands +# Added trace_calls, trace_run, step_to_call commands +# Changed hook-stop so it checks $SHOW_CONTEXT variable +# +# Version 5 +# Added bpm, dump_bin, dump_hex, bp_alloc commands +# Added 'assemble' by elaine, 'gas_asm' by mong +# Added Tip Topics for aspiring users ;) +# +# Version 4 +# Added eflags-changing insns by pusillus +# Added bp, nop, null, and int3 patch commands, also hook-stop +# +# Version 3 +# Incorporated elaine's if/else goodness into the hex/ascii dump +# +# Version 2 +# Radix bugfix by elaine \ No newline at end of file diff --git a/tools/grub.cfg b/tools/grub.cfg new file mode 100644 index 000000000..0dd855df6 --- /dev/null +++ b/tools/grub.cfg @@ -0,0 +1,5 @@ +set timeout=15 +set default=0 +menuentry "SimpleKernel" { + multiboot2 /boot/kernel.elf "KERNEL_ELF" +} diff --git a/tools/install.sh b/tools/install.sh new file mode 100644 index 000000000..e45b4fb51 --- /dev/null +++ b/tools/install.sh @@ -0,0 +1,186 @@ +#!/bin/bash + +# This file is a part of Simple-XX/SimpleKernel +# (https://github.com/Simple-XX/SimpleKernel). +# +# run.sh for Simple-XX/SimpleKernel. +# 在虚拟机中运行内核 + +# shell 执行出错时终止运行 +set -e +# 输出实际执行内容 +# set -x + +# 命令行使用方式 +help() { + echo "Usage:" + echo "run.sh [-t target arch] [-s simulator]" + echo "Description:" + echo "-t, 'riscv64', 'i386', 'x86_64', 'arm', 'aarch64'. riscv64 as default" + echo "-s, 'qemu'" + exit 1 +} + +# 如果没有传入参数或参数过多则退出 +if [ $# == 0 ] || [ $# -gt 4 ]; then + help + exit 1 +fi + +# 解析参数 +while getopts 't:s:h' opt; do + case $opt in + t) + TARGET="$OPTARG" + ;; + s) + SIMULATOR="$OPTARG" + ;; + h) + help + ;; + ?) + echo "missing options,pls check!" + exit 1 + ;; + esac +done + +# 如果没有确定必要参数则报错 +# 参数不为空 +if [ -z "$TARGET" ] || [ -z "$SIMULATOR" ]; then + help + exit 1 +fi + +# 判断是否合法 +# 目标架构 +targets=( +riscv64 +i386 +x86_64 +arm +aarch64 +) +if [[ ! "${targets[*]}" =~ $TARGET ]]; then + echo "$TARGET not exists" + help + exit 1 +fi +# 模拟器 +simulators=( +qemu +) +if [[ ! "${simulators[*]}" =~ $SIMULATOR ]]; then + echo "$SIMULATOR not exists" + help + exit 1 +fi + +# 宿主机器架构 +HOST_ARCH=$(uname -m) +# 宿主机器系统 +HOST_SYSTEM=$(uname -s) + +# 输出信息 +echo "host arch: $HOST_ARCH" +echo "host system: $HOST_SYSTEM" +echo "target arch: $TARGET" +echo "target simulator: $SIMULATOR" + +# 根据参数与机器信息确认依赖 +# 宿主机器为 x86_64 +if [ "${HOST_ARCH}" == "x86_64" ]; then + # 宿主机器为 linux + if [ "${HOST_SYSTEM}" == "Linux" ]; then + # target 为 riscv64 + if [ "${TARGET}" == "riscv64" ]; then + echo 1 + # target 为 arm/aarch64 + elif [ "${TARGET}" == "arm" ] || [ "${TARGET}" == "aarch64" ]; then + echo 1 + # target 为 i386/x86_64 + elif [ "${TARGET}" == "i386" ] || [ "${TARGET}" == "x86_64" ]; then + echo 1 + fi + # 宿主机器为 macos + elif [ "${HOST_SYSTEM}" == "Darwin" ]; then + # target 为 riscv64 + if [ "${TARGET}" == "riscv64" ]; then + echo 1 + # target 为 arm/aarch64 + elif [ "${TARGET}" == "arm" ] || [ "${TARGET}" == "aarch64" ]; then + echo 1 + # target 为 i386/x86_64 + elif [ "${TARGET}" == "i386" ] || [ "${TARGET}" == "x86_64" ]; then + echo 1 + fi + fi +# 宿主机器为 arm64 +elif [ "${HOST_ARCH}" == "arm64" ]; then + # 宿主机器为 linux + if [ "${HOST_SYSTEM}" == "Linux" ]; then + # target 为 riscv64 + if [ "${TARGET}" == "riscv64" ]; then + echo 1 + # target 为 arm/aarch64 + elif [ "${TARGET}" == "arm" ] || [ "${TARGET}" == "aarch64" ]; then + echo 1 + # target 为 i386/x86_64 + elif [ "${TARGET}" == "i386" ] || [ "${TARGET}" == "x86_64" ]; then + echo 1 + fi + # 宿主机器为 macos + elif [ "${HOST_SYSTEM}" == "Darwin" ]; then + # 安装通用依赖 + # make + if ! command -v make &> /dev/null; then + echo "make could not found." + echo "Installing make..." + # 安装 make + brew install make + echo "make installed." + fi + # cmake + if ! command -v cmake &> /dev/null; then + echo "cmake could not found." + echo "Installing cmake..." + # 安装 cmake + brew install cmake + echo "cmake installed." + fi + # qemu + if ! command -v qemu-system-riscv64 &> /dev/null; then + echo "qemu could not found." + echo "Installing qemu..." + # 安装 qemu + brew install qemu + echo "qemu installed." + fi + # target 为 riscv64 + if [ "${TARGET}" == "riscv64" ]; then + # riscv64-unknown-elf-gcc + if ! command -v riscv64-unknown-elf-gcc &> /dev/null; then + echo "riscv64-unknown-elf-gcc could not found." + echo "Installing riscv64-unknown-elf-gcc..." + # 安装 riscv64-unknown-elf-gcc + brew tap riscv-software-src/riscv + brew install riscv-software-src/riscv/riscv-gnu-toolchain + echo "riscv64-unknown-elf-gcc installed." + fi + # target 为 arm/aarch64 + elif [ "${TARGET}" == "arm" ] || [ "${TARGET}" == "aarch64" ]; then + echo 1 + # target 为 i386/x86_64 + elif [ "${TARGET}" == "i386" ] || [ "${TARGET}" == "x86_64" ]; then + # x86_64-elf-gcc + if ! command -v x86_64-elf-gcc &> /dev/null; then + echo "x86_64-elf-gcc could not found." + echo "Installing x86_64-elf-gcc..." + # 安装 x86_64-elf-gcc + brew install x86_64-elf-gcc + echo "x86_64-elf-gcc installed." + fi + fi + fi +fi diff --git a/tools/opensbi b/tools/opensbi deleted file mode 160000 index f41196a9d..000000000 --- a/tools/opensbi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f41196a9d245f024a87a08e7d159ca6dc0a6c298 diff --git a/tools/opensbi/.clang-format b/tools/opensbi/.clang-format new file mode 100644 index 000000000..c80c0aa98 --- /dev/null +++ b/tools/opensbi/.clang-format @@ -0,0 +1,16 @@ +AlignConsecutiveAssignments: true +AlignEscapedNewlines: Left +AlignTrailingComments: true +AllowShortFunctionsOnASingleLine: None +BraceWrapping: + AfterFunction: true +BreakBeforeBraces: Custom +BreakStringLiterals: false +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +IndentWidth: 8 +ReflowComments: false +SortIncludes: false +SpacesInContainerLiterals: false +TabWidth: 8 +UseTab: Always diff --git a/tools/opensbi/.gitignore b/tools/opensbi/.gitignore new file mode 100644 index 000000000..c11afd384 --- /dev/null +++ b/tools/opensbi/.gitignore @@ -0,0 +1,13 @@ +# Object files +*.o +*.a +*.dep + +#Build & install directories +build/ +install/ + +# Development friendly files +tags +cscope* +*.swp diff --git a/tools/opensbi/CONTRIBUTORS.md b/tools/opensbi/CONTRIBUTORS.md new file mode 100644 index 000000000..afae1251d --- /dev/null +++ b/tools/opensbi/CONTRIBUTORS.md @@ -0,0 +1,27 @@ + +List of OpenSBI Contributors (Alphabetically sorted) +==================================================== + +* **[Western Digital Corporation](https://www.wdc.com/)** + * Project initiator and maintainer + * Copyright (c) 2019 Western Digital Corporation or its affiliates + +* Alistair Francis + +* Andreas Schwab + +* Anup Patel + +* Atish Patra + +* Bin Meng + +* Damien Le Moal + +* Karsten Merker + +* Nick Kossifidis + +* Shawn Chang + +* Xiang Wang diff --git a/tools/opensbi/COPYING.BSD b/tools/opensbi/COPYING.BSD new file mode 100644 index 000000000..26972c8a4 --- /dev/null +++ b/tools/opensbi/COPYING.BSD @@ -0,0 +1,25 @@ +The 2-Clause BSD License +SPDX short identifier: BSD-2-Clause + +Copyright (c) 2019 Western Digital Corporation or its affiliates and other +contributors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/opensbi/Kconfig b/tools/opensbi/Kconfig new file mode 100644 index 000000000..acfc13888 --- /dev/null +++ b/tools/opensbi/Kconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: BSD-2-Clause + +mainmenu "OpenSBI $(OPENSBI_PLATFORM) Configuration" + +config OPENSBI_SRC_DIR + string + option env="OPENSBI_SRC_DIR" + +config OPENSBI_PLATFORM + string + option env="OPENSBI_PLATFORM" + +config OPENSBI_PLATFORM_SRC_DIR + string + option env="OPENSBI_PLATFORM_SRC_DIR" + +menu "Platform Options" +source "$(OPENSBI_PLATFORM_SRC_DIR)/Kconfig" +endmenu + +source "$(OPENSBI_SRC_DIR)/lib/sbi/Kconfig" + +source "$(OPENSBI_SRC_DIR)/lib/utils/Kconfig" + +source "$(OPENSBI_SRC_DIR)/firmware/Kconfig" diff --git a/tools/opensbi/Makefile b/tools/opensbi/Makefile new file mode 100644 index 000000000..92203c5a2 --- /dev/null +++ b/tools/opensbi/Makefile @@ -0,0 +1,677 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2019 Western Digital Corporation or its affiliates. +# +# Authors: +# Anup Patel +# + +# Select Make Options: +# o Do not use make's built-in rules +# o Do not print "Entering directory ..."; +MAKEFLAGS += -r --no-print-directory + +# Readlink -f requires GNU readlink +ifeq ($(shell uname -s),Darwin) +READLINK ?= greadlink +else +READLINK ?= readlink +endif + +# Find out source, build, and install directories +src_dir=$(CURDIR) +ifdef O + build_dir=$(shell $(READLINK) -f $(O)) +else + build_dir=$(CURDIR)/build +endif +ifeq ($(build_dir),$(CURDIR)) +$(error Build directory is same as source directory.) +endif +install_root_dir_default=$(CURDIR)/install +ifdef I + install_root_dir=$(shell $(READLINK) -f $(I)) +else + install_root_dir=$(install_root_dir_default)/usr +endif +ifeq ($(install_root_dir),$(CURDIR)) +$(error Install root directory is same as source directory.) +endif +ifeq ($(install_root_dir),$(build_dir)) +$(error Install root directory is same as build directory.) +endif +ifdef PLATFORM_DIR + platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR)) + ifdef PLATFORM + platform_parent_dir=$(platform_dir_path) + else + PLATFORM=$(shell basename $(platform_dir_path)) + platform_parent_dir=$(shell realpath ${platform_dir_path}/..) + endif +else + platform_parent_dir=$(src_dir)/platform +endif +ifndef PLATFORM_DEFCONFIG +PLATFORM_DEFCONFIG=defconfig +endif + +# Check if verbosity is ON for build process +CMD_PREFIX_DEFAULT := @ +ifeq ($(V), 1) + CMD_PREFIX := +else + CMD_PREFIX := $(CMD_PREFIX_DEFAULT) +endif + +# Setup path of directories +export platform_subdir=$(PLATFORM) +export platform_src_dir=$(platform_parent_dir)/$(platform_subdir) +export platform_build_dir=$(build_dir)/platform/$(platform_subdir) +export include_dir=$(CURDIR)/include +export libsbi_dir=$(CURDIR)/lib/sbi +export libsbiutils_dir=$(CURDIR)/lib/utils +export firmware_dir=$(CURDIR)/firmware + +# Setup variables for kconfig +ifdef PLATFORM +export PYTHONDONTWRITEBYTECODE=1 +export KCONFIG_DIR=$(platform_build_dir)/kconfig +export KCONFIG_AUTOLIST=$(KCONFIG_DIR)/auto.list +export KCONFIG_AUTOHEADER=$(KCONFIG_DIR)/autoconf.h +export KCONFIG_AUTOCMD=$(KCONFIG_DIR)/auto.conf.cmd +export KCONFIG_CONFIG=$(KCONFIG_DIR)/.config +# Additional exports for include paths in Kconfig files +export OPENSBI_SRC_DIR=$(src_dir) +export OPENSBI_PLATFORM=$(PLATFORM) +export OPENSBI_PLATFORM_SRC_DIR=$(platform_src_dir) +endif + +# Find library version +OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'` +OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'` +OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi) + +# Setup compilation commands +ifneq ($(LLVM),) +CC = clang +AR = llvm-ar +LD = ld.lld +OBJCOPY = llvm-objcopy +else +ifdef CROSS_COMPILE +CC = $(CROSS_COMPILE)gcc +AR = $(CROSS_COMPILE)ar +LD = $(CROSS_COMPILE)ld +OBJCOPY = $(CROSS_COMPILE)objcopy +else +CC ?= gcc +AR ?= ar +LD ?= ld +OBJCOPY ?= objcopy +endif +endif +CPP = $(CC) -E +AS = $(CC) +DTC = dtc + +ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),) +CC_IS_CLANG = y +else +CC_IS_CLANG = n +endif + +ifneq ($(shell $(LD) --version 2>&1 | head -n 1 | grep LLD),) +LD_IS_LLD = y +else +LD_IS_LLD = n +endif + +ifeq ($(CC_IS_CLANG),y) +ifneq ($(CROSS_COMPILE),) +CLANG_TARGET = --target=$(notdir $(CROSS_COMPILE:%-=%)) +endif +endif + +# Guess the compiler's XLEN +OPENSBI_CC_XLEN := $(shell TMP=`$(CC) $(CLANG_TARGET) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP}) + +# Guess the compiler's ABI and ISA +ifneq ($(CC_IS_CLANG),y) +OPENSBI_CC_ABI := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-abi=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP}) +OPENSBI_CC_ISA := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-arch=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP}) +endif + +# Setup platform XLEN +ifndef PLATFORM_RISCV_XLEN + ifeq ($(OPENSBI_CC_XLEN), 32) + PLATFORM_RISCV_XLEN = 32 + else + PLATFORM_RISCV_XLEN = 64 + endif +endif + +ifeq ($(CC_IS_CLANG),y) +ifeq ($(CROSS_COMPILE),) +CLANG_TARGET = --target=riscv$(PLATFORM_RISCV_XLEN)-unknown-elf +endif +endif + +ifeq ($(LD_IS_LLD),y) +RELAX_FLAG = -mno-relax +USE_LD_FLAG = -fuse-ld=lld +else +USE_LD_FLAG = -fuse-ld=bfd +endif + +# Check whether the linker supports creating PIEs +OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fPIE -nostdlib -Wl,-pie -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo y || echo n) + +# Check whether the compiler supports -m(no-)save-restore +CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y) + +# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions +CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y) + +# Build Info: +# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp +# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info +BUILD_INFO ?= n +ifeq ($(BUILD_INFO),y) +OPENSBI_BUILD_DATE_FMT = +%Y-%m-%d %H:%M:%S %z +ifdef SOURCE_DATE_EPOCH + OPENSBI_BUILD_TIME_STAMP ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" \ + "$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \ + date -u -r "$(SOURCE_DATE_EPOCH)" \ + "$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \ + date -u "$(OPENSBI_BUILD_DATE_FMT)") +else + OPENSBI_BUILD_TIME_STAMP ?= $(shell date "$(OPENSBI_BUILD_DATE_FMT)") +endif +OPENSBI_BUILD_COMPILER_VERSION=$(shell $(CC) -v 2>&1 | grep ' version ' | \ + sed 's/[[:space:]]*$$//') +endif + +# Setup list of objects.mk files +ifdef PLATFORM +platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi) +endif +libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -iname "objects.mk" | sort -r; fi) +libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi) +firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi) + +# The "make all" rule should always be first rule +.PHONY: all +all: + +# Include platform specific .config +ifdef PLATFORM +.PHONY: menuconfig +menuconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig + $(CMD_PREFIX)mkdir -p $(KCONFIG_DIR) + $(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/menuconfig.py $(src_dir)/Kconfig + $(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig + +.PHONY: savedefconfig +savedefconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig + $(CMD_PREFIX)mkdir -p $(KCONFIG_DIR) + $(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/savedefconfig.py --kconfig $(src_dir)/Kconfig --out $(KCONFIG_DIR)/defconfig + +$(KCONFIG_CONFIG): $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG) $(platform_src_dir)/Kconfig $(src_dir)/Kconfig + $(CMD_PREFIX)mkdir -p $(KCONFIG_DIR) + $(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/defconfig.py --kconfig $(src_dir)/Kconfig $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG) + $(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig + +$(KCONFIG_AUTOCMD): $(KCONFIG_CONFIG) + $(CMD_PREFIX)mkdir -p $(KCONFIG_DIR) + $(CMD_PREFIX)printf "%s: " $(KCONFIG_CONFIG) > $(KCONFIG_AUTOCMD) + $(CMD_PREFIX)cat $(KCONFIG_AUTOLIST) | tr '\n' ' ' >> $(KCONFIG_AUTOCMD) + +include $(KCONFIG_CONFIG) +include $(KCONFIG_AUTOCMD) +endif + +# Include all objects.mk files +ifdef PLATFORM +include $(platform-object-mks) +endif +include $(libsbi-object-mks) +include $(libsbiutils-object-mks) +include $(firmware-object-mks) + +# Setup list of objects +libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj)) +ifdef PLATFORM +libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(platform_build_dir)/lib/utils/$(obj)) +platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj)) +firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin)) +endif +firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf) +firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o) + +# Setup list of deps files for objects +deps-y=$(platform-objs-path-y:.o=.dep) +deps-y+=$(libsbi-objs-path-y:.o=.dep) +deps-y+=$(libsbiutils-objs-path-y:.o=.dep) +deps-y+=$(firmware-objs-path-y:.o=.dep) + +# Setup platform ABI, ISA and Code Model +ifndef PLATFORM_RISCV_ABI + ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1) + ifeq ($(PLATFORM_RISCV_XLEN), 32) + PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN) + else + PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN) + endif + else + PLATFORM_RISCV_ABI = $(OPENSBI_CC_ABI) + endif +endif +ifndef PLATFORM_RISCV_ISA + ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1) + ifeq ($(CC_SUPPORT_ZICSR_ZIFENCEI), y) + PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc_zicsr_zifencei + else + PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc + endif + else + PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA) + endif +endif +ifndef PLATFORM_RISCV_CODE_MODEL + PLATFORM_RISCV_CODE_MODEL = medany +endif + +# Setup install directories +ifdef INSTALL_INCLUDE_PATH + install_include_path=$(INSTALL_INCLUDE_PATH) +else + install_include_path=include +endif +ifdef INSTALL_LIB_PATH + install_lib_path=$(INSTALL_LIB_PATH) +else + ifneq ($(origin INSTALL_LIB_SUBDIR), undefined) + install_lib_subdir=$(INSTALL_LIB_SUBDIR) + else + install_lib_subdir=$(PLATFORM_RISCV_ABI) + endif + install_lib_path=lib$(subst 32,,$(PLATFORM_RISCV_XLEN))/$(install_lib_subdir) +endif +ifdef INSTALL_FIRMWARE_PATH + install_firmware_path=$(INSTALL_FIRMWARE_PATH) +else + install_firmware_path=share/opensbi/$(PLATFORM_RISCV_ABI) +endif +ifdef INSTALL_DOCS_PATH + install_docs_path=$(INSTALL_DOCS_PATH) +else + install_docs_path=share/opensbi/docs +endif + +# Setup compilation commands flags +ifeq ($(CC_IS_CLANG),y) +GENFLAGS += $(CLANG_TARGET) +GENFLAGS += -Wno-unused-command-line-argument +endif +GENFLAGS += -I$(platform_src_dir)/include +GENFLAGS += -I$(include_dir) +ifneq ($(OPENSBI_VERSION_GIT),) +GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\"" +endif +ifeq ($(BUILD_INFO),y) +GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\"" +GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\"" +endif +ifdef PLATFORM +GENFLAGS += -include $(KCONFIG_AUTOHEADER) +endif +GENFLAGS += $(libsbiutils-genflags-y) +GENFLAGS += $(platform-genflags-y) +GENFLAGS += $(firmware-genflags-y) + +CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -O2 +CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align +# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE +ifeq ($(CC_SUPPORT_SAVE_RESTORE),y) +CFLAGS += -mno-save-restore +endif +CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA) +CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL) +CFLAGS += $(RELAX_FLAG) +CFLAGS += $(GENFLAGS) +CFLAGS += $(platform-cflags-y) +CFLAGS += -fno-pie -no-pie +CFLAGS += $(firmware-cflags-y) + +CPPFLAGS += $(GENFLAGS) +CPPFLAGS += $(platform-cppflags-y) +CPPFLAGS += $(firmware-cppflags-y) + +ASFLAGS = -g -Wall -nostdlib +ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align +# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE +ifeq ($(CC_SUPPORT_SAVE_RESTORE),y) +ASFLAGS += -mno-save-restore +endif +ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA) +ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL) +ASFLAGS += $(RELAX_FLAG) +ifneq ($(CC_IS_CLANG),y) +ifneq ($(RELAX_FLAG),) +ASFLAGS += -Wa,$(RELAX_FLAG) +endif +endif +ASFLAGS += $(GENFLAGS) +ASFLAGS += $(platform-asflags-y) +ASFLAGS += $(firmware-asflags-y) + +ARFLAGS = rcs + +ELFFLAGS += $(USE_LD_FLAG) +ELFFLAGS += -Wl,--build-id=none -Wl,-N +ELFFLAGS += $(platform-ldflags-y) +ELFFLAGS += $(firmware-ldflags-y) + +MERGEFLAGS += -r +ifeq ($(LD_IS_LLD),y) +MERGEFLAGS += -b elf +else +MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv +endif +MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv + +DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp + +# Setup functions for compilation +define dynamic_flags +-I$(shell dirname $(2)) -D__OBJNAME__=$(subst -,_,$(shell basename $(1) .o)) +endef +merge_objs = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " MERGE $(subst $(build_dir)/,,$(1))"; \ + $(LD) $(MERGEFLAGS) $(2) -o $(1) +merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " MERGE-DEP $(subst $(build_dir)/,,$(1))"; \ + cat $(2) > $(1) +copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " COPY $(subst $(build_dir)/,,$(1))"; \ + cp -f $(2) $(1) +inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \ + cp -f $(2) $(1) +inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \ + mkdir -p $(1)/$(3); \ + for file in $(4) ; do \ + rel_file=`echo $$file | sed -e 's@$(2)/$(subst $(install_firmware_path),platform,$(3))@@'`; \ + dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \ + dest_dir=`dirname $$dest_file`; \ + echo " INSTALL "$(3)"/"`echo $$rel_file`; \ + mkdir -p $$dest_dir; \ + cp -f $$file $$dest_file; \ + done \ + fi +inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \ + echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \ + cp -rf $(2) $(1) +compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " CPP $(subst $(build_dir)/,,$(1))"; \ + $(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1) +compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \ + printf %s `dirname $(1)`/ > $(1) && \ + $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \ + -MM $(2) >> $(1) || rm -f $(1) +compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " CC $(subst $(build_dir)/,,$(1))"; \ + $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1) +compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \ + printf %s `dirname $(1)`/ > $(1) && \ + $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \ + -MM $(2) >> $(1) || rm -f $(1) +compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " AS $(subst $(build_dir)/,,$(1))"; \ + $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1) +compile_elf = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " ELF $(subst $(build_dir)/,,$(1))"; \ + $(CC) $(CFLAGS) $(3) $(ELFFLAGS) -Wl,-T$(2) -o $(1) +compile_ar = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " AR $(subst $(build_dir)/,,$(1))"; \ + $(AR) $(ARFLAGS) $(1) $(2) +compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " OBJCOPY $(subst $(build_dir)/,,$(1))"; \ + $(OBJCOPY) -S -O binary $(2) $(1) +compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " DTC $(subst $(build_dir)/,,$(1))"; \ + $(CPP) $(DTSCPPFLAGS) $(2) | $(DTC) -O dtb -i `dirname $(2)` -o $(1) +compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " D2C $(subst $(build_dir)/,,$(1))"; \ + $(if $($(2)-varalign-$(3)),$(eval D2C_ALIGN_BYTES := $($(2)-varalign-$(3))),$(eval D2C_ALIGN_BYTES := $(4))) \ + $(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \ + $(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \ + $(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1) +compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " CARRAY $(subst $(build_dir)/,,$(1))"; \ + $(eval CARRAY_VAR_LIST := $(carray-$(subst .c,,$(shell basename $(1)))-y)) \ + $(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1) +compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ + echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \ + echo "$(1:.dep=$(2)): $(3)" >> $(1) + +targets-y = $(build_dir)/lib/libsbi.a +ifdef PLATFORM +targets-y += $(platform_build_dir)/lib/libplatsbi.a +endif +targets-y += $(firmware-bins-path-y) + +# The default "make all" rule +.PHONY: all +all: $(targets-y) + +# Preserve all intermediate files +.SECONDARY: + +# Rules for lib/sbi sources +$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y) + $(call compile_ar,$@,$^) + +$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y) + $(call compile_ar,$@,$^) + +$(build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG) + $(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG)) + $(call compile_gen_dep,$@,.o,$(@:.dep=.c)) + +$(build_dir)/%.c: $(src_dir)/%.carray + $(call compile_carray,$@,$<) + +$(build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG) + $(call compile_cc_dep,$@,$<) + +$(build_dir)/%.o: $(src_dir)/%.c + $(call compile_cc,$@,$<) + +$(build_dir)/%.o: $(build_dir)/%.c + $(call compile_cc,$@,$<) + +ifeq ($(BUILD_INFO),y) +$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE + $(call compile_cc,$@,$<) +endif + +$(build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG) + $(call compile_as_dep,$@,$<) + +$(build_dir)/%.o: $(src_dir)/%.S + $(call compile_as,$@,$<) + +# Rules for platform sources +$(platform_build_dir)/%.dep: $(platform_src_dir)/%.carray $(KCONFIG_CONFIG) + $(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG)) + $(call compile_gen_dep,$@,.o,$(@:.dep=.c)) + +$(platform_build_dir)/%.c: $(platform_src_dir)/%.carray + $(call compile_carray,$@,$<) + +$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c $(KCONFIG_CONFIG) + $(call compile_cc_dep,$@,$<) + +$(platform_build_dir)/%.o: $(platform_src_dir)/%.c $(KCONFIG_CONFIG) + $(call compile_cc,$@,$<) + +$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S + $(call compile_as_dep,$@,$<) + +$(platform_build_dir)/%.o: $(platform_src_dir)/%.S + $(call compile_as,$@,$<) + +$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts $(KCONFIG_CONFIG) + $(call compile_gen_dep,$@,.dtb,$< $(KCONFIG_CONFIG)) + $(call compile_gen_dep,$@,.c,$(@:.dep=.dtb)) + $(call compile_gen_dep,$@,.o,$(@:.dep=.c)) + +$(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb + $(call compile_d2c,$@,platform,$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<))),16,dt,$<) + +$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts + $(call compile_dts,$@,$<) + +# Rules for lib/utils and firmware sources +$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf + $(call compile_objcopy,$@,$<) + +$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a + $(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a) + +$(platform_build_dir)/%.ld: $(src_dir)/%.ldS + $(call compile_cpp,$@,$<) + +$(platform_build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG) + $(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG)) + $(call compile_gen_dep,$@,.o,$(@:.dep=.c)) + +$(platform_build_dir)/%.c: $(src_dir)/%.carray + $(call compile_carray,$@,$<) + +$(platform_build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG) + $(call compile_cc_dep,$@,$<) + +$(platform_build_dir)/%.o: $(src_dir)/%.c + $(call compile_cc,$@,$<) + +$(platform_build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG) + $(call compile_as_dep,$@,$<) + +$(platform_build_dir)/%.o: $(src_dir)/%.S + $(call compile_as,$@,$<) + +# Rule for "make docs" +$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex + $(CMD_PREFIX)mkdir -p $(build_dir)/docs + $(CMD_PREFIX)$(MAKE) -C $(build_dir)/docs/latex +$(build_dir)/docs/latex/refman.tex: $(build_dir)/docs/doxygen.cfg + $(CMD_PREFIX)mkdir -p $(build_dir)/docs + $(CMD_PREFIX)doxygen $(build_dir)/docs/doxygen.cfg +$(build_dir)/docs/doxygen.cfg: $(src_dir)/docs/doxygen.cfg + $(CMD_PREFIX)mkdir -p $(build_dir)/docs + $(CMD_PREFIX)cat docs/doxygen.cfg | sed -e "s#@@SRC_DIR@@#$(src_dir)#" -e "s#@@BUILD_DIR@@#$(build_dir)#" -e "s#@@OPENSBI_MAJOR@@#$(OPENSBI_VERSION_MAJOR)#" -e "s#@@OPENSBI_MINOR@@#$(OPENSBI_VERSION_MINOR)#" > $(build_dir)/docs/doxygen.cfg +.PHONY: docs +docs: $(build_dir)/docs/latex/refman.pdf + +# Dependency files should only be included after default Makefile rules +# They should not be included for any "xxxconfig" or "xxxclean" rule +all-deps-1 = $(if $(findstring config,$(MAKECMDGOALS)),,$(deps-y)) +all-deps-2 = $(if $(findstring clean,$(MAKECMDGOALS)),,$(all-deps-1)) +-include $(all-deps-2) + +# Include external dependency of firmwares after default Makefile rules +include $(src_dir)/firmware/external_deps.mk + +# Convenient "make run" command for emulated platforms +.PHONY: run +run: all +ifneq ($(platform-runcmd),) + $(platform-runcmd) $(RUN_ARGS) +else +ifdef PLATFORM + @echo "Platform $(PLATFORM) doesn't specify a run command" + @false +else + @echo Run command only available when targeting a platform + @false +endif +endif + +install_targets-y = install_libsbi +ifdef PLATFORM +install_targets-y += install_libplatsbi +install_targets-y += install_firmwares +endif + +# Rule for "make install" +.PHONY: install +install: $(install_targets-y) + +.PHONY: install_libsbi +install_libsbi: $(build_dir)/lib/libsbi.a + $(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi) + $(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a) + +.PHONY: install_libplatsbi +install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a + $(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a) + +.PHONY: install_firmwares +install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y) + $(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y)) + $(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y)) + +.PHONY: install_docs +install_docs: $(build_dir)/docs/latex/refman.pdf + $(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf) + +.PHONY: cscope +cscope: + $(CMD_PREFIX)find \ + "$(src_dir)/firmware" \ + "$(src_dir)/include" \ + "$(src_dir)/lib" \ + "$(platform_src_dir)" \ + -name "*.[chS]" -print > cscope.files + $(CMD_PREFIX)echo "$(KCONFIG_AUTOHEADER)" >> cscope.files + $(CMD_PREFIX)cscope -bkq -i cscope.files -f cscope.out + +# Rule for "make clean" +.PHONY: clean +clean: + $(CMD_PREFIX)mkdir -p $(build_dir) + $(if $(V), @echo " RM $(build_dir)/*.o") + $(CMD_PREFIX)find $(build_dir) -type f -name "*.o" -exec rm -rf {} + + $(if $(V), @echo " RM $(build_dir)/*.a") + $(CMD_PREFIX)find $(build_dir) -type f -name "*.a" -exec rm -rf {} + + $(if $(V), @echo " RM $(build_dir)/*.elf") + $(CMD_PREFIX)find $(build_dir) -type f -name "*.elf" -exec rm -rf {} + + $(if $(V), @echo " RM $(build_dir)/*.bin") + $(CMD_PREFIX)find $(build_dir) -type f -name "*.bin" -exec rm -rf {} + + $(if $(V), @echo " RM $(build_dir)/*.dtb") + $(CMD_PREFIX)find $(build_dir) -type f -name "*.dtb" -exec rm -rf {} + + +# Rule for "make distclean" +.PHONY: distclean +distclean: clean + $(CMD_PREFIX)mkdir -p $(build_dir) + $(if $(V), @echo " RM $(build_dir)/*.dep") + $(CMD_PREFIX)find $(build_dir) -type f -name "*.dep" -exec rm -rf {} + +ifeq ($(build_dir),$(CURDIR)/build) + $(if $(V), @echo " RM $(build_dir)") + $(CMD_PREFIX)rm -rf $(build_dir) +endif +ifeq ($(install_root_dir),$(install_root_dir_default)/usr) + $(if $(V), @echo " RM $(install_root_dir_default)") + $(CMD_PREFIX)rm -rf $(install_root_dir_default) +endif + $(if $(V), @echo " RM $(src_dir)/cscope*") + $(CMD_PREFIX)rm -f $(src_dir)/cscope* + +.PHONY: FORCE +FORCE: diff --git a/tools/opensbi/README.md b/tools/opensbi/README.md new file mode 100644 index 000000000..895bbf27a --- /dev/null +++ b/tools/opensbi/README.md @@ -0,0 +1,383 @@ +RISC-V Open Source Supervisor Binary Interface (OpenSBI) +======================================================== + +Copyright and License +--------------------- + +The OpenSBI project is copyright (c) 2019 Western Digital Corporation +or its affiliates and other contributors. + +It is distributed under the terms of the BSD 2-clause license +("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*). +A copy of this license with OpenSBI copyright can be found in the file +[COPYING.BSD]. + +All source files in OpenSBI contain the 2-Clause BSD license SPDX short +identifier in place of the full license text. + +``` +SPDX-License-Identifier: BSD-2-Clause +``` + +This enables machine processing of license information based on the SPDX +License Identifiers that are available on the [SPDX] web site. + +OpenSBI source code also contains code reused from other projects as listed +below. The original license text of these projects is included in the source +files where the reused code is present. + +* The libfdt source code is disjunctively dual licensed + (GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI + under the terms of the BSD 2-Clause license. Any contributions to this + code must be made under the terms of both licenses. + +See also the [third party notices] file for more information. + +Introduction +------------ + +The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface +between: + +1. A platform-specific firmware running in M-mode and a bootloader, a + hypervisor or a general-purpose OS executing in S-mode or HS-mode. +2. A hypervisor running in HS-mode and a bootloader or a general-purpose OS + executing in VS-mode. + +The *RISC-V SBI specification* is maintained as an independent project by the +RISC-V Foundation on [Github]. + +The goal of the OpenSBI project is to provide an open-source reference +implementation of the RISC-V SBI specifications for platform-specific firmwares +executing in M-mode (case 1 mentioned above). An OpenSBI implementation can be +easily extended by RISC-V platform and system-on-chip vendors to fit a +particular hardware configuration. + +The main component of OpenSBI is provided in the form of a platform-independent +static library **libsbi.a** implementing the SBI interface. A firmware or +bootloader implementation can link against this library to ensure conformance +with the SBI interface specifications. *libsbi.a* also defines an interface for +integrating with platform-specific operations provided by the platform firmware +implementation (e.g. console access functions, inter-processor interrupt +control, etc). + +To illustrate the use of the *libsbi.a* library, OpenSBI also provides a set of +platform-specific support examples. For each example, a platform-specific +static library *libplatsbi.a* can be compiled. This library implements +SBI call processing by integrating *libsbi.a* with the necessary +platform-dependent hardware manipulation functions. For all supported platforms, +OpenSBI also provides several runtime firmware examples built using the platform +*libplatsbi.a*. These example firmwares can be used to replace the legacy +*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders +such as [U-Boot]. + +Supported SBI version +--------------------- +Currently, OpenSBI fully supports SBI specification *v0.2*. OpenSBI also +supports Hart State Management (HSM) SBI extension starting from OpenSBI v0.7. +HSM extension allows S-mode software to boot all the harts a defined order +rather than legacy method of random booting of harts. As a result, many +required features such as CPU hotplug, kexec/kdump can also be supported easily +in S-mode. HSM extension in OpenSBI is implemented in a non-backward compatible +manner to reduce the maintenance burden and avoid confusion. That's why, any +S-mode software using OpenSBI will not be able to boot more than 1 hart if HSM +extension is not supported in S-mode. + +Linux kernel already supports SBI v0.2 and HSM SBI extension starting from +**v5.7-rc1**. If you are using an Linux kernel older than **5.7-rc1** or any +other S-mode software without HSM SBI extension, you should stick to OpenSBI +v0.6 to boot all the harts. For a UMP systems, it doesn't matter. + +N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension, +as it doesn't need to boot all the harts. The operating system should be +capable enough to bring up all other non-booting harts using HSM extension. + +Required Toolchain and Packages +------------------------------- + +OpenSBI can be compiled natively or cross-compiled on a x86 host. For +cross-compilation, you can build your own toolchain, download a prebuilt one +from the [Bootlin toolchain repository] or install a distribution-provided +toolchain; if you opt to use LLVM/Clang, most distribution toolchains will +support cross-compiling for RISC-V using the same toolchain as your native +LLVM/Clang toolchain due to LLVM's ability to support multiple backends in the +same binary, so is often an easy way to obtain a working cross-compilation +toolchain. + +Basically, we prefer toolchains with Position Independent Executable (PIE) +support like *riscv64-linux-gnu-gcc*, *riscv64-unknown-freebsd-gcc*, or +*Clang/LLVM* as they generate PIE firmware images that can run at arbitrary +address with appropriate alignment. If a bare-metal GNU toolchain (e.g. +*riscv64-unknown-elf-gcc*) is used, static linked firmware images are +generated instead. *Clang/LLVM* can still generate PIE images if a bare-metal +triple is used (e.g. *-target riscv64-unknown-elf*). + +Please note that only a 64-bit version of the toolchain is available in +the Bootlin toolchain repository for now. + +In addition to a toolchain, OpenSBI also requires the following packages on +the host: + +1. device-tree-compiler: The device tree compiler for compiling device + tree sources (DTS files). +2. python3: The python 3.0 (or compatible) language support for various + scripts. + +Building and Installing the OpenSBI Platform-Independent Library +---------------------------------------------------------------- + +The OpenSBI platform-independent static library *libsbi.a* can be compiled +natively or it can be cross-compiled on a host with a different base +architecture than RISC-V. + +For cross-compiling, the environment variable *CROSS_COMPILE* must be defined +to specify the name prefix of the RISC-V compiler toolchain executables, e.g. +*riscv64-linux-gnu-* if the gcc executable used is *riscv64-linux-gnu-gcc*. + +To build *libsbi.a* simply execute: +``` +make +``` + +All compiled binaries as well as the resulting *libsbi.a* static library file +will be placed in the *build/lib* directory. To specify an alternate build root +directory path, run: +``` +make O= +``` + +To generate files to be installed for using *libsbi.a* in other projects, run: +``` +make install +``` + +This will create the *install* directory with all necessary include files +copied under the *install/include* directory and the library file copied into +the *install/lib* directory. To specify an alternate installation root +directory path, run: +``` +make I= install +``` + +Building and Installing a Reference Platform Static Library and Firmware +------------------------------------------------------------------------ + +When the *PLATFORM=* argument is specified on the make command +line, the platform-specific static library *libplatsbi.a* and firmware examples +are built for the platform ** present in the directory +*platform* in the OpenSBI top directory. For example, to compile the platform +library and the firmware examples for the QEMU RISC-V *virt* machine, +** should be *generic*. + +To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported +platforms, run: +``` +make PLATFORM= +``` + +An alternate build directory path can also be specified: +``` +make PLATFORM= O= +``` + +The platform-specific library *libplatsbi.a* will be generated in the +*build/platform//lib* directory. The platform firmware files +will be under the *build/platform//firmware* directory. +The compiled firmwares will be available in two different formats: an ELF file +and an expanded image file. + +To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run: +``` +make PLATFORM= install +``` + +This will copy the compiled platform-specific libraries and firmware files +under the *install/platform//* directory. An alternate +install root directory path can be specified as follows: +``` +make PLATFORM= I= install +``` + +In addition, platform-specific configuration options can be specified with the +top-level make command line. These options, such as *PLATFORM_* or +*FW_*, are platform-specific and described in more details in the +*docs/platform/.md* files and +*docs/firmware/.md* files. + +All OpenSBI platforms support Kconfig style build-time configuration. Users +can change the build-time configuration of a platform using a graphical +interface as follows: +``` +make PLATFORM= menuconfig +``` + +Alternately, an OpenSBI platform can have multiple default configurations +and users can select a custom default configuration as follows: +``` +make PLATFORM= PLATFORM_DEFCONFIG= +``` + +Building 32-bit / 64-bit OpenSBI Images +--------------------------------------- +By default, building OpenSBI generates 32-bit or 64-bit images based on the +supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set +to *riscv64-linux-gnu-*, 64-bit OpenSBI images will be generated. If building +32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is +pre-configured to generate 32-bit RISC-V codes, like *riscv32-linux-gnu-*. + +However it's possible to explicitly specify the image bits we want to build with +a given RISC-V toolchain. This can be done by setting the environment variable +*PLATFORM_RISCV_XLEN* to the desired width, for example: + +``` +export CROSS_COMPILE=riscv64-linux-gnu- +export PLATFORM_RISCV_XLEN=32 +``` + +will generate 32-bit OpenSBI images. And vice vesa. + +Building with Clang/LLVM +------------------------ + +OpenSBI can also be built with Clang/LLVM. To build with just Clang but keep +the default binutils (which will still use the *CROSS_COMPILE* prefix if +defined), override the *CC* make variable with: +``` +make CC=clang +``` + +To build with a full LLVM-based toolchain, not just Clang, enable the *LLVM* +option with: +``` +make LLVM=1 +``` + +When using Clang, *CROSS_COMPILE* often does not need to be defined unless +using GNU binutils with prefixed binary names. *PLATFORM_RISCV_XLEN* will be +used to infer a default triple to pass to Clang, so if *PLATFORM_RISCV_XLEN* +itself defaults to an undesired value then prefer setting that rather than the +full triple via *CROSS_COMPILE*. If *CROSS_COMPILE* is nonetheless defined, +rather than being used as a prefix for the executable name, it will instead be +passed via the `--target` option with the trailing `-` removed, so must be a +valid triple. + +These can also be mixed; for example using a GCC cross-compiler but LLVM +binutils would be: +``` +make CC=riscv64-linux-gnu-gcc LLVM=1 +``` + +These variables must be passed for all the make invocations described in this +document. + +NOTE: Using Clang with a `riscv*-linux-gnu` GNU binutils linker has been seen +to produce broken binaries with missing relocations; it is therefore currently +recommended that this combination be avoided or *FW_PIC=n* be used to disable +building OpenSBI as a position-independent binary. + +Building with timestamp and compiler info +----------------------------------------- + +When doing development, we may want to know the build time and compiler info +for debug purpose. OpenSBI can also be built with timestamp and compiler info. +To build with those info and print it out at boot time, we can just simply add +`BUILD_INFO=y`, like: +``` +make BUILD_INFO=y +``` + +But if you have used `BUILD_INFO=y`, and want to switch back to `BUILD_INFO=n`, +you must do +``` +make clean +``` +before the next build. + +NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will violate +[reproducible builds]. This definition is ONLY for development and debug +purpose, and should NOT be used in a product which follows "reproducible +builds". + +Contributing to OpenSBI +----------------------- + +The OpenSBI project encourages and welcomes contributions. Contributions should +follow the rules described in the OpenSBI [Contribution Guideline] document. +In particular, all patches sent should contain a Signed-off-by tag. + +The [Contributors List] document provides a list of individuals and +organizations actively contributing to the OpenSBI project. + +Documentation +------------- + +Detailed documentation of various aspects of OpenSBI can be found under the +*docs* directory. The documentation covers the following topics. + +* [Contribution Guideline]: Guideline for contributing code to OpenSBI project +* [Library Usage]: API documentation of OpenSBI static library *libsbi.a* +* [Platform Requirements]: Requirements for using OpenSBI on a platform +* [Platform Support Guide]: Guideline for implementing support for new platforms +* [Platform Documentation]: Documentation of the platforms currently supported. +* [Firmware Documentation]: Documentation for the different types of firmware + examples build supported by OpenSBI. +* [Domain Support]: Documentation for the OpenSBI domain support which helps + users achieve system-level partitioning using OpenSBI. + +OpenSBI source code is also well documented. For source level documentation, +doxygen style is used. Please refer to the [Doxygen manual] for details on this +format. + +Doxygen can be installed on Linux distributions using *.deb* packages using +the following command. +``` +sudo apt-get install doxygen doxygen-latex doxygen-doc doxygen-gui graphviz +``` + +For *.rpm* based Linux distributions, the following commands can be used. +``` +sudo yum install doxygen doxygen-latex doxywizard graphviz +``` +or +``` +sudo yum install doxygen doxygen-latex doxywizard graphviz +``` + +To build a consolidated *refman.pdf* of all documentation, run: +``` +make docs +``` +or +``` +make O= docs +``` + +the resulting *refman.pdf* will be available under the directory +*/docs/latex*. To install this file, run: +``` +make install_docs +``` +or +``` +make I= install_docs +``` + +*refman.pdf* will be installed under */docs*. + +[Github]: https://github.com/riscv/riscv-sbi-doc +[U-Boot]: https://www.denx.de/wiki/U-Boot/SourceCode +[Bootlin toolchain repository]: https://toolchains.bootlin.com/ +[COPYING.BSD]: COPYING.BSD +[SPDX]: http://spdx.org/licenses/ +[Contribution Guideline]: docs/contributing.md +[Contributors List]: CONTRIBUTORS.md +[Library Usage]: docs/library_usage.md +[Platform Requirements]: docs/platform_requirements.md +[Platform Support Guide]: docs/platform_guide.md +[Platform Documentation]: docs/platform/platform.md +[Firmware Documentation]: docs/firmware/fw.md +[Domain Support]: docs/domain_support.md +[Doxygen manual]: http://www.doxygen.nl/manual/index.html +[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk +[third party notices]: ThirdPartyNotices.md +[reproducible builds]: https://reproducible-builds.org diff --git a/tools/opensbi/ThirdPartyNotices.md b/tools/opensbi/ThirdPartyNotices.md new file mode 100644 index 000000000..1162d4361 --- /dev/null +++ b/tools/opensbi/ThirdPartyNotices.md @@ -0,0 +1,18 @@ +Copyright (c) 2019 Western Digital Corporation or its affiliates. + +Third Party Notices +=================== + +This project includes or partly uses code from the following open source +software subject to the following open source licenses. + +libfdt +------ + +Copyright (C) 2016 Free Electrons +Copyright (C) 2016 NextThing Co. + +The libfdt source code is disjunctively dual licensed (GPL-2.0+ or +BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of +the BSD 2-Clause license. The full text of this license can be found in the +file [COPYING.BSD](COPYING.BSD). diff --git a/tools/opensbi/docs/contributing.md b/tools/opensbi/docs/contributing.md new file mode 100644 index 000000000..78d909e47 --- /dev/null +++ b/tools/opensbi/docs/contributing.md @@ -0,0 +1,84 @@ +OpenSBI Contribution Guideline +============================== + +All contributions to OpenSBI can be sent in the following ways: +1. Email patches to the OpenSBI mailing list at `opensbi@lists.infradead.org` +2. GitHub Pull Requests (PRs) to the [OpenSBI main repository] + +To join the OpenSBI mailing list, please visit the [OpenSBI infradead page]. + +The OpenSBI maintainers prefer patches via the OpenSBI mailing list +(option 1 above) so that they are visible to a wider audience. All +accepted patches on the OpenSBI mailing list will be taken by any of +the OpenSBI maintainers and merged into the [OpenSBI main repository] +using GitHub PRs. + +All contributed work must follow the following rules: +1. OpenSBI code should be written in accordance to the [Linux coding style]. +2. This project embraces the [Developer Certificate of Origin (DCO)] for +contributions. This means that you must agree to the following prior to +submitting patches: if you agree with this developer certificate you +acknowledge this by adding a Signed-off-by tag to your patch commit log. +Every submitted patch must have this tag. +3. A commit message must have a subject line, followed by a blank line, +followed by a description of the patch content. A blank line and the author +Signed-off-by tag must follow this description. +4. A commit subject line must start with a prefix followed by a ":". Common +prefixes are for example "lib:", "platform:", "firmware:", "docs:", "utils:" +and "top:". +5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull +requests to avoid creating unnecessary merge commits. +6. Maintainers should avoid creating branches directly in the main +riscv/opensbi repository. Instead, prefer using a fork of the riscv/opensbi main +repository and branches within that fork to create pull requests. +7. A maintainer cannot merge his own pull requests in the riscv/opensbi main +repository. +8. A pull request must get at least one review from a maintainer. +9. A pull request must spend at least 24 hours in review to allow for other +developers to review. + +----------------------------------------------------------------------- + +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +----------------------------------------------------------------------- + +[OpenSBI main repository]: https://github.com/riscv/opensbi +[OpenSBI infradead page]: http://lists.infradead.org/mailman/listinfo/opensbi +[Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html +[Developer Certificate of Origin (DCO)]: http://developercertificate.org/ diff --git a/tools/opensbi/docs/domain_support.md b/tools/opensbi/docs/domain_support.md new file mode 100644 index 000000000..8963b57e3 --- /dev/null +++ b/tools/opensbi/docs/domain_support.md @@ -0,0 +1,314 @@ +OpenSBI Domain Support +====================== + +An OpenSBI domain is a system-level partition (subset) of underlying hardware +having its own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI +will try to achieve secure isolation between domains using RISC-V platform +features such as PMP, ePMP, IOPMP, SiFive Shield, etc. + +Important entities which help implement OpenSBI domain support are: + +* **struct sbi_domain_memregion** - Representation of a domain memory region +* **struct sbi_hartmask** - Representation of domain HART set +* **struct sbi_domain** - Representation of a domain instance + +Each HART of a RISC-V platform must have an OpenSBI domain assigned to it. +The OpenSBI platform support is responsible for populating domains and +providing HART id to domain mapping. The OpenSBI domain support will by +default assign **the ROOT domain** to all HARTs of a RISC-V platform, so +it is not mandatory for the OpenSBI platform support to populate domains. + +Domain Memory Region +-------------------- + +A domain memory region is represented by **struct sbi_domain_memregion** in +OpenSBI and has following details: + +* **order** - The size of a memory region is **2 ^ order** where **order** + must be **3 <= order <= __riscv_xlen** +* **base** - The base address of a memory region is **2 ^ order** + aligned start address +* **flags** - The flags of a memory region represent memory type (i.e. + RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc.) + +Domain Instance +--------------- + +A domain instance is represented by **struct sbi_domain** in OpenSBI and +has following details: + +* **index** - Logical index of this domain +* **name** - Name of this domain +* **assigned_harts** - HARTs assigned to this domain +* **possible_harts** - HARTs possible in this domain +* **regions** - Array of memory regions terminated by a memory region + with order zero +* **boot_hartid** - HART id of the HART booting this domain. The domain + boot HART will be started at boot-time if boot HART is possible and + assigned for this domain. +* **next_addr** - Address of the next booting stage for this domain +* **next_arg1** - Arg1 (or 'a1' register) of the next booting stage for + this domain +* **next_mode** - Privilege mode of the next booting stage for this + domain. This can be either S-mode or U-mode. +* **system_reset_allowed** - Is domain allowed to reset the system? + +The memory regions represented by **regions** in **struct sbi_domain** have +following additional constraints to align with RISC-V PMP requirements: + +* A memory region to protect OpenSBI firmware from S-mode and U-mode + should always be present +* For two overlapping memory regions, one should be sub-region of another +* Two overlapping memory regions should not be of same size +* Two overlapping memory regions cannot have same flags +* Memory access checks on overlapping address should prefer smallest + overlapping memory region flags. + +ROOT Domain +----------- + +**The ROOT domain** is the default OpenSBI domain which is assigned by +default to all HARTs of a RISC-V platform. The OpenSBI domain support +will hand-craft **the ROOT domain** very early at boot-time in the +following manner: + +* **index** - Logical index of the ROOT domain is always zero +* **name** - Name of the ROOT domain is "root" +* **assigned_harts** - At boot-time all valid HARTs of a RISC-V platform + are assigned the ROOT domain which changes later based on OpenSBI + platform support +* **possible_harts** - All valid HARTs of a RISC-V platform are possible + HARTs of the ROOT domain +* **regions** - Two memory regions available to the ROOT domain: + **A)** A memory region to protect OpenSBI firmware from S-mode and U-mode + **B)** A memory region of **order=__riscv_xlen** allowing S-mode and + U-mode access to full memory address space +* **boot_hartid** - Coldboot HART is the HART booting the ROOT domain +* **next_addr** - Next booting stage address in coldboot HART scratch + space is the next address for the ROOT domain +* **next_arg1** - Next booting stage arg1 in coldboot HART scratch space + is the next arg1 for the ROOT domain +* **next_mode** - Next booting stage mode in coldboot HART scratch space + is the next mode for the ROOT domain +* **system_reset_allowed** - The ROOT domain is allowed to reset the system + +Domain Effects +-------------- + +Few noteworthy effects of a system partitioned into domains are as follows: + +* At any point in time, a HART is running in exactly one OpenSBI domain context +* The SBI IPI and RFENCE calls from HART A are restricted to the HARTs in + domain assigned to HART A +* The SBI HSM calls which try to change/read state of HART B from HART A will + only work if both HART A and HART B are assigned same domain +* A HART running in S-mode or U-mode can only access memory based on the + memory regions of the domain assigned to the HART + +Domain Device Tree Bindings +--------------------------- + +The OpenSBI domains can be described in the **device tree (DT) blob** (or +flattened device tree) passed to the OpenSBI firmwares by the previous +booting stage. This allows OpenSBI platform support to parse and populate +OpenSBI domains from the device tree blob (or flattened device tree). + +### Domain Configuration Node + +All OpenSBI domain description related DT nodes should be under the domain +configuration DT node. The **/chosen** DT node is the preferred parent of +the domain configuration DT node. + +The DT properties of a domain configuration DT node are as follows: + +* **compatible** (Mandatory) - The compatible string of the domain + configuration. This DT property should have value *"opensbi,domain,config"* + +### Domain Memory Region Node + +The domain memory region DT node describes details of a memory region and +can be pointed by multiple domain instance DT nodes. The access permissions +of the memory region are specified separately in domain instance node. + +The DT properties of a domain memory region DT node are as follows: + +* **compatible** (Mandatory) - The compatible string of the domain memory + region. This DT property should have value *"opensbi,domain,memregion"* +* **base** (Mandatory) - The base address of the domain memory region. This + DT property should have a **2 ^ order** aligned 64 bit address (i.e. two + DT cells). +* **order** (Mandatory) - The order of the domain memory region. This DT + property should have a 32 bit value (i.e. one DT cell) in the range + **3 <= order <= __riscv_xlen**. +* **mmio** (Optional) - A boolean flag representing whether the domain + memory region is a memory-mapped I/O (MMIO) region. +* **devices** (Optional) - The list of device DT node phandles for devices + which fall under this domain memory region. + +### Domain Instance Node + +The domain instance DT node describes set of possible HARTs, set of memory +regions, and other details of a domain instance. + +The DT properties of a domain instance DT node are as follows: + +* **compatible** (Mandatory) - The compatible string of the domain instance. + This DT property should have value *"opensbi,domain,instance"* +* **possible-harts** (Optional) - The list of CPU DT node phandles for the + the domain instance. This list represents the possible HARTs of the + domain instance. +* **regions** (Optional) - The list of domain memory region DT node phandle + and access permissions for the domain instance. Each list entry is a pair + of DT node phandle and access permissions. The access permissions are + represented as a 32bit bitmask having bits: **readable** (BIT[0]), + **writeable** (BIT[1]), **executable** (BIT[2]), and **m-mode** (BIT[3]). +* **boot-hart** (Optional) - The DT node phandle of the HART booting the + domain instance. If coldboot HART is assigned to the domain instance then + this DT property is ignored and the coldboot HART is assumed to be the + boot HART of the domain instance. +* **next-arg1** (Optional) - The 64 bit next booting stage arg1 for the + domain instance. If this DT property is not available and coldboot HART + is not assigned to the domain instance then **0x0** is used as default + value. If this DT property is not available and coldboot HART is assigned + to the domain instance then **next booting stage arg1 of coldboot HART** + is used as default value. +* **next-addr** (Optional) - The 64 bit next booting stage address for the + domain instance. If this DT property is not available and coldboot HART + is not assigned to the domain instance then **0x0** is used as default + value. If this DT property is not available and coldboot HART is assigned + to the domain instance then **next booting stage address of coldboot HART** + is used as default value. +* **next-mode** (Optional) - The 32 bit next booting stage mode for the + domain instance. The possible values of this DT property are: **0x1** + (s-mode), and **0x0** (u-mode). If this DT property is not available + and coldboot HART is not assigned to the domain instance then **0x1** + is used as default value. If this DT property is not available and + coldboot HART is assigned to the domain instance then **next booting + stage mode of coldboot HART** is used as default value. +* **system-reset-allowed** (Optional) - A boolean flag representing + whether the domain instance is allowed to do system reset. + +### Assigning HART To Domain Instance + +By default, all HARTs are assigned to **the ROOT domain**. The OpenSBI +platform support can provide the HART to domain instance assignment using +platform specific callback. + +The HART to domain instance assignment can be parsed from the device tree +using optional DT property **opensbi,domain** in each CPU DT node. The +value of DT property **opensbi,domain** is the DT phandle of the domain +instance DT node. If **opensbi,domain** DT property is not specified then +corresponding HART is assigned to **the ROOT domain**. + +### Domain Configuration Only Accessible to OpenSBI + +The software running inside a domain instance should only be aware of +devices and hardware resources accessible to itself. + +To hide domain configuration from domain instances, the following should +be done: + +* The previous booting stage should preferably provide a separate device + tree for each domain instance and mention location of device tree in + respective domain instance DT nodes using **next-arg1** DT property. +* If domain assigned to a HART does not have separate device tree then + OpenSBI platform support should remove all domain configuration details + from the device tree passed by previous booting stage before passing it + to the next booting stage. + +### Example + +``` + chosen { + opensbi-domains { + compatible = "opensbi,domain,config"; + + tmem: tmem { + compatible = "opensbi,domain,memregion"; + base = <0x0 0x80100000>; + order = <20>; + }; + + tuart: tuart { + compatible = "opensbi,domain,memregion"; + base = <0x0 0x10011000>; + order = <12>; + mmio; + devices = <&uart1>; + }; + + allmem: allmem { + compatible = "opensbi,domain,memregion"; + base = <0x0 0x0>; + order = <64>; + }; + + tdomain: trusted-domain { + compatible = "opensbi,domain,instance"; + possible-harts = <&cpu0>; + regions = <&tmem 0x7>, <&tuart 0x7>; + boot-hart = <&cpu0>; + next-arg1 = <0x0 0x0>; + next-addr = <0x0 0x80100000>; + next-mode = <0x0>; + system-reset-allowed; + }; + + udomain: untrusted-domain { + compatible = "opensbi,domain,instance"; + possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>; + regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x7>; + }; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <10000000>; + + cpu0: cpu@0 { + device_type = "cpu"; + reg = <0x00>; + compatible = "riscv"; + opensbi-domain = <&tdomain>; + ... + }; + + cpu1: cpu@1 { + device_type = "cpu"; + reg = <0x01>; + compatible = "riscv"; + opensbi-domain = <&udomain>; + ... + }; + + cpu2: cpu@2 { + device_type = "cpu"; + reg = <0x02>; + compatible = "riscv"; + opensbi-domain = <&udomain>; + ... + }; + + cpu3: cpu@3 { + device_type = "cpu"; + reg = <0x03>; + compatible = "riscv"; + opensbi-domain = <&udomain>; + ... + }; + + cpu4: cpu@4 { + device_type = "cpu"; + reg = <0x04>; + compatible = "riscv"; + opensbi-domain = <&udomain>; + ... + }; + }; + + uart1: serial@10011000 { + ... + }; +``` diff --git a/tools/opensbi/docs/doxygen.cfg b/tools/opensbi/docs/doxygen.cfg new file mode 100644 index 000000000..82f31a7ae --- /dev/null +++ b/tools/opensbi/docs/doxygen.cfg @@ -0,0 +1,2462 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "RISC-V OpenSBI" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = "v@@OPENSBI_MAJOR@@.@@OPENSBI_MINOR@@" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Open source implemenation of the supervisor binary interface" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = @@BUILD_DIR@@/docs + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @@SRC_DIR@@/README.md \ + @@SRC_DIR@@/docs/contributing.md \ + @@SRC_DIR@@/docs/platform_guide.md \ + @@SRC_DIR@@/docs/platform_requirements.md \ + @@SRC_DIR@@/docs/library_usage.md \ + @@SRC_DIR@@/docs/domain_support.md \ + @@SRC_DIR@@/docs/firmware \ + @@SRC_DIR@@/docs/platform \ + @@SRC_DIR@@/include \ + @@SRC_DIR@@/lib + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.h \ + *.md + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /