mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 17:19:47 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
617ddfee93 | ||
|
|
464858dbb4 | ||
|
|
6de12c1032 | ||
|
|
a16eb76f5e | ||
|
|
021c53ba32 | ||
|
|
38921dc46b | ||
|
|
054da021d0 | ||
|
|
199662071a | ||
|
|
572ac7d100 | ||
|
|
d461c6f47d | ||
|
|
67b19ae733 | ||
|
|
c4c812c154 | ||
|
|
388e236360 | ||
|
|
f2c8ddbbe3 | ||
|
|
d1d4388201 | ||
|
|
6ffed14b9c | ||
|
|
7f6d0b8709 | ||
|
|
d7b1919b29 | ||
|
|
f86e6f8eb0 | ||
|
|
7e780e57d4 | ||
|
|
9a5a13854d | ||
|
|
a795017416 | ||
|
|
8e3b361aeb | ||
|
|
f9dd5683a4 | ||
|
|
e38a6e7996 | ||
|
|
ddfaf3fee0 | ||
|
|
0dbf01bf1d | ||
|
|
3a599bfbe1 | ||
|
|
89fc95fefd | ||
|
|
8e37ee2598 | ||
|
|
d9b4f647d8 | ||
|
|
0dde3a0e70 | ||
|
|
32643e9fa7 | ||
|
|
0a92c78035 | ||
|
|
118db71121 | ||
|
|
a0410f0170 | ||
|
|
d44a7dc603 | ||
|
|
2ba6b0158f | ||
|
|
f3effcb703 | ||
|
|
03b476f943 | ||
|
|
8b3e368e9a | ||
|
|
df6b384e31 | ||
|
|
280bdec817 | ||
|
|
2c5e7ec547 | ||
|
|
fdcb8b2f7e | ||
|
|
04c6bc478e | ||
|
|
cc2c1893c5 | ||
|
|
3093f0e467 | ||
|
|
3609f65de3 | ||
|
|
9906f299bb | ||
|
|
1d8f37a2f0 | ||
|
|
e677460d14 | ||
|
|
4937843f70 | ||
|
|
b003888696 | ||
|
|
2ca491dc56 | ||
|
|
9aa353d88b | ||
|
|
c67faf61df | ||
|
|
165c6b37e2 | ||
|
|
dcd626edf8 | ||
|
|
f032b5570b | ||
|
|
ea081b262c | ||
|
|
fae1c32267 | ||
|
|
9b6718ac99 | ||
|
|
cd672e251f | ||
|
|
500a47bc2f | ||
|
|
e4d25d68e4 | ||
|
|
f31a98d50a | ||
|
|
2816df59b2 | ||
|
|
a05ce3ad9d | ||
|
|
7c8df05042 | ||
|
|
4c77acdfcf | ||
|
|
b74b974cfd | ||
|
|
07cef612c3 | ||
|
|
deaef81463 | ||
|
|
c638eabfe0 | ||
|
|
8e68384e15 | ||
|
|
2f4ca71f26 | ||
|
|
07004ebf04 | ||
|
|
086d7006da | ||
|
|
0a51241f7a | ||
|
|
c68f6599e5 | ||
|
|
af3f62a71a | ||
|
|
6cf9b9e0fc | ||
|
|
1d4b452839 | ||
|
|
c2db3b703a | ||
|
|
edb03b89d8 | ||
|
|
7724664b13 | ||
|
|
1df4296208 |
No files matched your search
@@ -0,0 +1,27 @@
|
||||
# Run this command to always ignore formatting commits in git blame
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
|
||||
# Upgraded clang-format to 19.0.0git
|
||||
89fc95fefd40413706ff1bdaac2e8d98b328dbf1
|
||||
# vim c++ filetype in modelines
|
||||
04c6bc478e082263d67c41bedbd033dde2d429eb
|
||||
# Ran clang-format
|
||||
f032b5570b4cd87c6bb4abb54c0b98e69c939955
|
||||
# Applied clang-format update to repo
|
||||
6e6fc38935054db0534d5af4fb99c6193305b946
|
||||
# revert retabbing
|
||||
2b315626f3af765cdfbc61114647412cdb798b3a
|
||||
# more modeline errata
|
||||
3a8e01a77a7c97af0b16fb1651b230cee7f7d4c6
|
||||
# fix more vi modelines
|
||||
2fc507c98f53a76718f61f9a36602f86b5ac0cc9
|
||||
# flip et/noet in modelines
|
||||
e16a7d8f3b8f906c3ef76e79f57f3adfc7f25186
|
||||
# fix vi modelines
|
||||
394d998315f613a888cc6b6c051d4163bdf5cd6f
|
||||
# clang-format
|
||||
c0eacf2eb1e1c0b3bd4f71f12fef258f5b249c3f
|
||||
# ape-m1 formatting cleanup
|
||||
da8baf2aa5ce93b958aca90a0ae69f537806324b
|
||||
# Run clang-format on most sources
|
||||
369f9740de4534c28d0e81ab2afc99decbb9a3e6
|
||||
@@ -0,0 +1,59 @@
|
||||
name: Low Severity Bugs
|
||||
description: Used to report low severity bugs in cosmopolitan (e.g. cosmetic issues, non critical UI glitches)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "low severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. [email protected]
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
@@ -0,0 +1,59 @@
|
||||
name: Medium Severity Bug
|
||||
description: Used to report medium severity bugs in cosmopolitan (e.g. Malfunctioning Features but generally still useable)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "medium severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. [email protected]
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
@@ -0,0 +1,59 @@
|
||||
name: High Severity Bug
|
||||
description: Used to report high severity bugs in cosmopolitan (e.g. Malfunctioning features hindering important common workflow)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "high severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. [email protected]
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
@@ -0,0 +1,59 @@
|
||||
name: Critical Severity Bug
|
||||
description: Used to report critical severity bugs in cosmopolitan (e.g. Crashing, Corrupted, Dataloss)
|
||||
title: "Bug: "
|
||||
labels: ["bug", "critical severity"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
Please include information about your system, the steps to reproduce the bug,
|
||||
and the version of cosmopolitan that you are using.
|
||||
If possible, please provide a minimal code example that reproduces the bug.
|
||||
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
|
||||
for additional technical logging that may allow us to narrow down where the fault occurred.
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact Details
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. [email protected]
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of our software are you running? (use `--version` to get a version string)
|
||||
placeholder: "cosmocc (GCC) 12.3.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: What operating system are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
@@ -0,0 +1,51 @@
|
||||
name: Enhancement template
|
||||
description: Used to request enhancements for cosmopolitan
|
||||
title: "Feature Request: "
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
[Please post your idea first in Discussion if there is not yet a consensus for this enhancement request. This will help to keep this issue tracker focused on enhancements that the community has agreed needs to be implemented.](https://github.com/jart/cosmopolitan/discussions/categories/ideas)
|
||||
|
||||
- type: checkboxes
|
||||
id: prerequisites
|
||||
attributes:
|
||||
label: Prerequisites
|
||||
description: Please confirm the following before submitting your enhancement request.
|
||||
options:
|
||||
- label: I am running the latest code. Mention the version if possible as well.
|
||||
required: true
|
||||
- label: I carefully followed the [README.md](https://github.com/jart/cosmopolitan/blob/master/README.md).
|
||||
required: true
|
||||
- label: I searched using keywords relevant to my issue to make sure that I am creating a new issue that is not already open (or closed).
|
||||
required: true
|
||||
- label: I reviewed the [Discussions](https://github.com/jart/cosmopolitan/discussions), and have a new and useful enhancement to share.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
attributes:
|
||||
label: Feature Description
|
||||
description: Please provide a detailed written description of what you were trying to do, and what you expected `cosmopolitan` to do as an enhancement.
|
||||
placeholder: Detailed description of the enhancement
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: Please provide a detailed written description of reasons why this feature is necessary and how it is useful to `cosmopolitan` users.
|
||||
placeholder: Explanation of why this feature is needed and its benefits
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: possible-implementation
|
||||
attributes:
|
||||
label: Possible Implementation
|
||||
description: If you have an idea as to how it can be implemented, please write a detailed description. Feel free to give links to external sources or share visuals that might be helpful to understand the details better.
|
||||
placeholder: Detailed description of potential implementation
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Research
|
||||
description: Track new technical research area
|
||||
title: "Research: "
|
||||
labels: ["research"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Don't forget to check for any [duplicate research issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3A%22research+%F0%9F%94%AC%22)
|
||||
|
||||
- type: checkboxes
|
||||
id: research-stage
|
||||
attributes:
|
||||
label: Research Stage
|
||||
description: Track general state of this research ticket
|
||||
options:
|
||||
- label: Background Research (Let's try to avoid reinventing the wheel)
|
||||
- label: Hypothesis Formed (How do you think this will work and it's effect?)
|
||||
- label: Strategy / Implementation Forming
|
||||
- label: Analysis of results
|
||||
- label: Debrief / Documentation (So people in the future can learn from us)
|
||||
|
||||
- type: textarea
|
||||
id: background
|
||||
attributes:
|
||||
label: Previous existing literature and research
|
||||
description: Whats the current state of the art and whats the motivation for this research?
|
||||
|
||||
- type: textarea
|
||||
id: hypothesis
|
||||
attributes:
|
||||
label: Hypothesis
|
||||
description: How do you think this will work and it's effect?
|
||||
|
||||
- type: textarea
|
||||
id: implementation
|
||||
attributes:
|
||||
label: Implementation
|
||||
description: Got an approach? e.g. a PR ready to go?
|
||||
|
||||
- type: textarea
|
||||
id: analysis
|
||||
attributes:
|
||||
label: Analysis
|
||||
description: How does the proposed implementation behave?
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
@@ -0,0 +1,28 @@
|
||||
name: Refactor (Maintainers)
|
||||
description: Used to track refactoring opportunities
|
||||
title: "Refactor: "
|
||||
labels: ["refactor"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Don't forget to [check for existing refactor issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3Arefactoring) in case it's already covered.
|
||||
Also you may want to check [Pull request refactor label as well](https://github.com/jart/cosmopolitan/pulls?q=is%3Aopen+is%3Apr+label%3Arefactoring) for duplicates too.
|
||||
|
||||
- type: textarea
|
||||
id: background-description
|
||||
attributes:
|
||||
label: Background Description
|
||||
description: Please provide a detailed written description of the pain points you are trying to solve.
|
||||
placeholder: Detailed description behind your motivation to request refactor
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: possible-approaches
|
||||
attributes:
|
||||
label: Possible Refactor Approaches
|
||||
description: If you have some idea of possible approaches to solve this problem. You may want to make it a todo list.
|
||||
placeholder: Your idea of possible refactoring opportunity/approaches
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,15 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: FAQ
|
||||
url: https://github.com/jart/cosmopolitan/wiki/FAQ
|
||||
about: Is your question a common one? You may want to check here first.
|
||||
- name: Got an idea?
|
||||
url: https://github.com/jart/cosmopolitan/discussions/categories/ideas
|
||||
about: Pop it there. It may then become an enhancement ticket.
|
||||
- name: Got a question?
|
||||
url: https://github.com/jart/cosmopolitan/discussions/categories/q-a
|
||||
about: Ask a question there!
|
||||
- name: Want to contribute?
|
||||
url: https://github.com/jart/cosmopolitan/wiki/contribute
|
||||
about: Head to the contribution guide page of the wiki for areas you can help with
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# https://github.com/actions/labeler
|
||||
|
||||
documentation:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- README.md
|
||||
- LICENSE
|
||||
- CONTRIBUTING.md
|
||||
- libc/README.md
|
||||
- tool/cosmocc/README.md
|
||||
- third_party/getopt/README.txt
|
||||
build:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- build/**
|
||||
- Makefile
|
||||
- '*/*.mk'
|
||||
examples:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: examples/**
|
||||
devops:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- .github/**
|
||||
- .clang-format
|
||||
dsp:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- dsp/**
|
||||
ape:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- ape/**
|
||||
libc:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- libc/**
|
||||
net:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- net/**
|
||||
third_party:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- third_party/**
|
||||
tool:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- tool/**
|
||||
@@ -0,0 +1,17 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: "jart/cosmopolitan"
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: '.github/labeler.yml'
|
||||
Vendored
-108
@@ -1,108 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++11",
|
||||
"forcedInclude": ["${workspaceFolder}/.vscode/vscode.h"],
|
||||
"defines": [
|
||||
"libcesque=",
|
||||
"pureconst=",
|
||||
"paramsnonnull(x)=",
|
||||
"alignas(x)",
|
||||
"alignof(x)",
|
||||
"artificial=",
|
||||
"__wur=",
|
||||
"mayalias=",
|
||||
"forceinline=",
|
||||
"forcealign(x)=",
|
||||
"scanfesque(x)=",
|
||||
"strftimeesque(x)=",
|
||||
"wontreturn=",
|
||||
"textreal=",
|
||||
"mallocesque=",
|
||||
"callocesque=",
|
||||
"vallocesque=",
|
||||
"reallocesque=",
|
||||
"strlenesque=",
|
||||
"memcpyesque=",
|
||||
"hasatleast=",
|
||||
"noinline=",
|
||||
"textexit=",
|
||||
"returnstwice=",
|
||||
"textwindows=",
|
||||
"privileged=",
|
||||
"dontinstrument=",
|
||||
"nodebuginfo=",
|
||||
"interruptfn=",
|
||||
"optimizespeed=",
|
||||
"forcealignargpointer=",
|
||||
"dontasan=",
|
||||
"dontubsan=",
|
||||
"donothing=",
|
||||
"nosideeffect=",
|
||||
"unreachable=",,
|
||||
"notpossible=",
|
||||
"thatispacked=",
|
||||
"dontthrow=",
|
||||
"dontcallback=",
|
||||
"relegated=",
|
||||
"hidden=",
|
||||
"textstartup=",
|
||||
"returnsnonnull=",
|
||||
"returnspointerwithnoaliases=",
|
||||
"printfesque(x)=",
|
||||
"attributeallocsize(x)=",
|
||||
"returnsaligned(x)=",
|
||||
"attributeallocalign(x)=",
|
||||
"nullterminated(x)="
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"cStandard": "gnu17",
|
||||
"compilerPath": "${workspaceFolder}/o/third_party/gcc/bin/x86_64-linux-musl-gcc",
|
||||
"compilerArgs": [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-fdebug-prefix-map=${workspaceFolder}=",
|
||||
"-frecord-gcc-switches",
|
||||
"-Wa,-W",
|
||||
"-Wa,-I.",
|
||||
"-Wa,--noexecstack",
|
||||
"-Og",
|
||||
"-g",
|
||||
"-gdescribe-dies",
|
||||
"-msse3",
|
||||
"-mno-red-zone",
|
||||
"-fno-math-errno",
|
||||
"-fno-trapping-math",
|
||||
"-fno-fp-int-builtin-inexact",
|
||||
"-fno-ident",
|
||||
"-fno-common",
|
||||
"-fno-gnu-unique",
|
||||
"-fstrict-aliasing",
|
||||
"-fstrict-overflow",
|
||||
"-fno-semantic-interposition",
|
||||
"-mno-omit-leaf-frame-pointer",
|
||||
"-fno-jump-tables",
|
||||
"-nostdinc",
|
||||
"-iquote."
|
||||
],
|
||||
"forcedInclude": [
|
||||
"libc/integral/normalize.inc"
|
||||
],
|
||||
"defines": [
|
||||
"COSMO",
|
||||
"MODE="
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
#define __VSCODE_INTELLISENSE__ 1
|
||||
#include "libc/integral/normalize.inc"
|
||||
@@ -133,7 +133,7 @@ endif
|
||||
|
||||
ifneq ($(findstring aarch64,$(MODE)),)
|
||||
ARCH = aarch64
|
||||
HOSTS ?= pi pi5 studio freebsdarm
|
||||
HOSTS ?= pi studio freebsdarm
|
||||
else
|
||||
ARCH = x86_64
|
||||
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10
|
||||
@@ -174,6 +174,7 @@ all: o
|
||||
o: o/$(MODE)
|
||||
o/$(MODE): \
|
||||
o/$(MODE)/ape \
|
||||
o/$(MODE)/ctl \
|
||||
o/$(MODE)/dsp \
|
||||
o/$(MODE)/net \
|
||||
o/$(MODE)/libc \
|
||||
@@ -255,6 +256,7 @@ include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
|
||||
include libc/proc/BUILD.mk # │ You can now use threads
|
||||
include libc/dlopen/BUILD.mk # │ You can now use processes
|
||||
include libc/thread/BUILD.mk # │ You can finally call malloc()
|
||||
include ctl/BUILD.mk # │
|
||||
include third_party/zlib/BUILD.mk # │
|
||||
include libc/stdio/BUILD.mk # │
|
||||
include tool/hello/BUILD.mk # │
|
||||
@@ -299,6 +301,7 @@ include tool/viz/lib/BUILD.mk
|
||||
include tool/args/BUILD.mk
|
||||
include test/math/BUILD.mk
|
||||
include test/posix/BUILD.mk
|
||||
include test/ctl/BUILD.mk
|
||||
include test/libcxx/BUILD.mk
|
||||
include test/tool/args/BUILD.mk
|
||||
include third_party/linenoise/BUILD.mk
|
||||
@@ -362,7 +365,6 @@ include test/libc/fmt/BUILD.mk
|
||||
include test/libc/time/BUILD.mk
|
||||
include test/libc/proc/BUILD.mk
|
||||
include test/libc/stdio/BUILD.mk
|
||||
include test/libc/release/BUILD.mk
|
||||
include test/libc/BUILD.mk
|
||||
include test/net/http/BUILD.mk
|
||||
include test/net/https/BUILD.mk
|
||||
@@ -452,6 +454,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||
LIBC_THREAD \
|
||||
LIBC_PROC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
CTL \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_DLOPEN \
|
||||
@@ -520,6 +523,7 @@ COSMOPOLITAN_H_PKGS = \
|
||||
|
||||
COSMOCC_PKGS = \
|
||||
$(COSMOPOLITAN_H_PKGS) \
|
||||
CTL \
|
||||
THIRD_PARTY_AARCH64 \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
@@ -542,15 +546,6 @@ COSMOPOLITAN_H_ROOT_HDRS = \
|
||||
libc/integral/normalize.inc \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
|
||||
|
||||
o/cosmopolitan.h.txt: Makefile
|
||||
$(file >$@, $(call uniq,$(COSMOPOLITAN_H_ROOT_HDRS)))
|
||||
|
||||
o/cosmopolitan.h: o/cosmopolitan.h.txt \
|
||||
$(wildcard libc/integral/*) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
|
||||
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup @$< >>$@
|
||||
|
||||
o/cosmopolitan.html: private .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.dbg \
|
||||
@@ -572,7 +567,6 @@ $(SRCS): \
|
||||
|
||||
ifeq ($(ARCH), x86_64)
|
||||
TOOLCHAIN_ARTIFACTS = \
|
||||
o/cosmopolitan.h \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
|
||||
@@ -162,7 +162,6 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/thread/tls.h \
|
||||
libc/intrin/asancodes.h \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
@@ -189,7 +188,6 @@ o/$(MODE)/ape/ape-copy-self.o: \
|
||||
libc/dce.h \
|
||||
libc/elf/def.h \
|
||||
libc/thread/tls.h \
|
||||
libc/intrin/asancodes.h \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
|
||||
+2
-2
@@ -1,6 +1,7 @@
|
||||
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
|
||||
│ vi: set et sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
ENTRY(_start)
|
||||
@@ -285,8 +286,7 @@ SECTIONS {
|
||||
|
||||
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
|
||||
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024;
|
||||
ape_stack_align = DEFINED(ape_stack_align) ? ape_stack_align : 16;
|
||||
ape_stack_round = -ape_stack_align;
|
||||
ape_stack_prot = PROT_READ | PROT_WRITE;
|
||||
|
||||
_tls_size = _tbss_end - _tdata_start;
|
||||
_tdata_size = _tdata_end - _tdata_start;
|
||||
|
||||
@@ -761,7 +761,7 @@ ape_phdrs:
|
||||
.quad 0
|
||||
.quad 0
|
||||
.quad 0
|
||||
.stub ape_stack_align,quad
|
||||
.quad 16
|
||||
|
||||
#if SupportsOpenbsd() || SupportsNetbsd()
|
||||
.long PT_NOTE
|
||||
@@ -1036,7 +1036,7 @@ ape_pe: .ascin "PE",4
|
||||
.quad ape_pe_base // ImageBase
|
||||
.long ape_pe_sectionalignment // SectionAlignment
|
||||
.long ape_pe_filealignment // FileAlignment
|
||||
.short v_ntversion // MajorOperatingSystemVersion
|
||||
.short 10 // MajorOperatingSystemVersion
|
||||
.short 0 // MinorOperatingSystemVersion
|
||||
.short 0 // MajorImageVersion
|
||||
.short 0 // MinorImageVersion
|
||||
|
||||
@@ -588,8 +588,6 @@ ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
|
||||
ape_stack_paddr = ape_ram_paddr + ape_ram_filesz;
|
||||
ape_stack_filesz = 0;
|
||||
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024;
|
||||
ape_stack_align = DEFINED(ape_stack_align) ? ape_stack_align : 16;
|
||||
ape_stack_round = -ape_stack_align;
|
||||
|
||||
ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr);
|
||||
ape_note_filesz = ape_note_end - ape_note;
|
||||
@@ -715,7 +713,6 @@ ape_idataz = LINK_WINDOWS ? RVA(ape_idata_iat) : 0;
|
||||
ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0;
|
||||
ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0;
|
||||
ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0;
|
||||
v_ntversion = LINK_WINDOWS ? 6 : 1;
|
||||
v_ntdllchar = LINK_WINDOWS ? 288 : 0;
|
||||
v_ntsubversion = LINK_WINDOWS ? 6 : 5;
|
||||
v_ntsubsystem = (LINK_WINDOWS
|
||||
|
||||
+21
-31
@@ -84,9 +84,10 @@
|
||||
/* clang-format on */
|
||||
#elif defined(__LINKER__)
|
||||
|
||||
#define BCX_NIBBLE(X) ((((X)&0xf) > 0x9) ? ((X)&0xf) + 0x37 : ((X)&0xf) + 0x30)
|
||||
#define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0))
|
||||
#define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0))
|
||||
#define BCX_NIBBLE(X) \
|
||||
((((X) & 0xf) > 0x9) ? ((X) & 0xf) + 0x37 : ((X) & 0xf) + 0x30)
|
||||
#define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0))
|
||||
#define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0))
|
||||
#define BCXSTUB(SYM, X) \
|
||||
HIDDEN(SYM##_bcx0 = BCX_INT16((X) >> 48)); \
|
||||
HIDDEN(SYM##_bcx1 = BCX_INT16((X) >> 32)); \
|
||||
@@ -98,12 +99,12 @@
|
||||
*
|
||||
* <p>This allows linker scripts to generate printf commands.
|
||||
*/
|
||||
#define BCO_OCTET(X) (((X)&0x7) + 0x30)
|
||||
#define BCO_OCTET(X) (((X) & 0x7) + 0x30)
|
||||
#define BCOB_UNIT(X) \
|
||||
((BCO_OCTET((X) >> 0) << 24) | (BCO_OCTET((X) >> 3) << 16) | \
|
||||
(BCO_OCTET(((X)&0xff) >> 6) << 8) | 0x5c)
|
||||
(BCO_OCTET(((X) & 0xff) >> 6) << 8) | 0x5c)
|
||||
|
||||
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I)*8)))
|
||||
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I) * 8)))
|
||||
#define PFSTUB2(SYM, X) \
|
||||
HIDDEN(SYM = (X)); \
|
||||
PFBYTE(SYM, X, 0); \
|
||||
@@ -140,23 +141,16 @@
|
||||
: (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \
|
||||
: (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \
|
||||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + \
|
||||
(X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + \
|
||||
((X) / 10) % 10 + \
|
||||
(X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + \
|
||||
((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + \
|
||||
(X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 ? 0x30303030 + \
|
||||
((X) / 1000) % 10 + \
|
||||
((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + \
|
||||
(X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
#define BCD_RIGHT(X) \
|
||||
(((X)) < 10000 ? 0x20202020 \
|
||||
: (X) < 100000 ? 0x20202030 + (X) % 10 \
|
||||
: (X) < 1000000 ? 0x20203030 + ((X) / 10) % 10 + (X) % 10 * 0x100 \
|
||||
: (X) < 10000000 ? 0x20303030 + ((X) / 100) % 10 + \
|
||||
((X) / 10) % 10 * 0x100 + (X) % 10 * 0x10000 \
|
||||
: (X) < 100000000 \
|
||||
? 0x30303030 + ((X) / 1000) % 10 + ((X) / 100) % 10 * 0x100 + \
|
||||
((X) / 10) % 10 * 0x10000 + (X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
* Laying out the GDT entries for a TSS for bare metal operation.
|
||||
@@ -165,15 +159,11 @@
|
||||
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
|
||||
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | \
|
||||
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||
0x2 << 52 | \
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | ((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | ((LIM) >> 16 << 48 & 0x000f000000000000) | 0x2 << 52 | \
|
||||
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||
#define TSSDESC_ENT1(BASE) \
|
||||
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
#define TSSDESC_ENT1(BASE) ((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* APE_MACROS_H_ */
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+12
-34
@@ -11,20 +11,20 @@
|
||||
#
|
||||
ifeq ($(MODE),)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
ifeq ($(MODE), x86_64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
@@ -38,13 +38,13 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), zero)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0
|
||||
OVERRIDE_CXXFLAGS += -O0
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-zero)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
OVERRIDE_CFLAGS += -O0 -fdce
|
||||
OVERRIDE_CXXFLAGS += -O0 -fdce
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
@@ -81,7 +81,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), opt)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O3 -fmerge-all-constants
|
||||
TARGET_ARCH ?= -march=native
|
||||
@@ -98,7 +98,7 @@ endif
|
||||
# - Turns off support for other operating systems
|
||||
#
|
||||
ifeq ($(MODE), optlinux)
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
|
||||
CONFIG_COPTS += -mred-zone
|
||||
@@ -127,32 +127,10 @@ TARGET_ARCH ?= -msse3
|
||||
PYFLAGS += -O1
|
||||
endif
|
||||
|
||||
# Asan Mode
|
||||
#
|
||||
# Safer binaries good for backend production serving.
|
||||
#
|
||||
# - `make MODE=asan`
|
||||
# - Memory safety
|
||||
# - Production worthy
|
||||
# - Backtraces
|
||||
# - Debuggability
|
||||
# - Larger binaries
|
||||
#
|
||||
ifeq ($(MODE), asan)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_CPPFLAGS += -D__SANITIZE_ADDRESS__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2 -DSYSDEBUG
|
||||
CONFIG_COPTS += -fsanitize=address
|
||||
TARGET_ARCH ?= -msse3
|
||||
QUOTA ?= -C64 -L300
|
||||
endif
|
||||
|
||||
# Debug Mode
|
||||
#
|
||||
# - `make MODE=dbg`
|
||||
# - Backtraces
|
||||
# - Enables asan
|
||||
# - Enables ubsan
|
||||
# - Stack canaries
|
||||
# - No optimization
|
||||
@@ -160,17 +138,17 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__ -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
|
||||
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
|
||||
CONFIG_COPTS += -fsanitize=undefined
|
||||
TARGET_ARCH ?= -msse3
|
||||
OVERRIDE_CCFLAGS += -fno-pie
|
||||
QUOTA ?= -C64 -L300
|
||||
endif
|
||||
ifeq ($(MODE), aarch64-dbg)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce
|
||||
CONFIG_COPTS += -fsanitize=undefined
|
||||
@@ -189,7 +167,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE), sysv)
|
||||
ENABLE_FTRACE = 1
|
||||
CONFIG_OFLAGS ?= -g
|
||||
CONFIG_OFLAGS ?= -g -ggdb
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
|
||||
TARGET_ARCH ?= -msse3
|
||||
|
||||
@@ -60,12 +60,10 @@ TMPSAFE = $(TMPDIR)/
|
||||
endif
|
||||
|
||||
BACKTRACES = \
|
||||
-fno-schedule-insns2 \
|
||||
-fno-optimize-sibling-calls \
|
||||
-mno-omit-leaf-frame-pointer
|
||||
|
||||
SANITIZER = \
|
||||
-fsanitize=address
|
||||
|
||||
NO_MAGIC = \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
@@ -144,12 +142,14 @@ DEFAULT_CFLAGS = \
|
||||
-std=gnu2x
|
||||
|
||||
DEFAULT_CXXFLAGS = \
|
||||
-std=gnu++20 \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-fuse-cxa-atexit \
|
||||
-Wno-int-in-bool-context \
|
||||
-Wno-narrowing \
|
||||
-Wno-literal-suffix
|
||||
-Wno-literal-suffix \
|
||||
-isystem third_party/libcxx
|
||||
|
||||
DEFAULT_ASFLAGS = \
|
||||
-W \
|
||||
@@ -256,12 +256,12 @@ LD.libs = \
|
||||
$(LIBS)
|
||||
|
||||
COMPILE.c.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(c.flags)
|
||||
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(cxx.flags)
|
||||
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cxx.flags) $(cpp.flags)
|
||||
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
|
||||
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
|
||||
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
|
||||
OBJECTIFY.c.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(c.flags)
|
||||
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
|
||||
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cxx.flags) $(cpp.flags) $(copt.flags)
|
||||
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
|
||||
OBJECTIFY.S.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags)
|
||||
PREPROCESS.flags = -E $(copt.flags) $(cc.flags) $(cpp.flags)
|
||||
|
||||
+8
-8
@@ -6,14 +6,14 @@ if [ -n "$OBJDUMP" ]; then
|
||||
fi
|
||||
|
||||
find_objdump() {
|
||||
if [ -x .cosmocc/3.3.2/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x .cosmocc/3.3.2/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3.2/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3.2/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/.cosmocc/3.3.2/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3.2/bin/$1-linux-musl-objdump"
|
||||
if [ -x .cosmocc/3.3.5/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x .cosmocc/3.3.5/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.3.5/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.3.5/bin/$1-linux-musl-objdump"
|
||||
else
|
||||
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
|
||||
exit 1
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
BasedOnStyle: Mozilla
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 80
|
||||
---
|
||||
Language: Cpp
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AlignTrailingComments: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
FixNamespaceComments: true
|
||||
---
|
||||
@@ -0,0 +1,49 @@
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
|
||||
|
||||
PKGS += CTL
|
||||
|
||||
CTL_ARTIFACTS += CTL_A
|
||||
CTL = $(CTL_A_DEPS) $(CTL_A)
|
||||
CTL_A = o/$(MODE)/ctl/ctl.a
|
||||
CTL_A_FILES := $(wildcard ctl/*)
|
||||
CTL_A_HDRS = $(filter %.h,$(CTL_A_FILES))
|
||||
CTL_A_SRCS = $(filter %.cc,$(CTL_A_FILES))
|
||||
CTL_A_OBJS = $(CTL_A_SRCS:%.cc=o/$(MODE)/%.o)
|
||||
|
||||
CTL_A_CHECKS = \
|
||||
$(CTL_A).pkg \
|
||||
$(CTL_A_HDRS:%=o/$(MODE)/%.okk) \
|
||||
|
||||
CTL_A_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_STR \
|
||||
|
||||
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(CTL_A): ctl/ \
|
||||
$(CTL_A).pkg \
|
||||
$(CTL_A_OBJS)
|
||||
|
||||
$(CTL_A).pkg: \
|
||||
$(CTL_A_OBJS) \
|
||||
$(foreach x,$(CTL_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
$(CTL_A_OBJS): private \
|
||||
OVERRIDE_CXXFLAGS += \
|
||||
-Wframe-larger-than=4096 \
|
||||
-Walloca-larger-than=4096 \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fexceptions \
|
||||
|
||||
CTL_LIBS = $(foreach x,$(CTL_ARTIFACTS),$($(x)))
|
||||
CTL_SRCS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_SRCS))
|
||||
CTL_HDRS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_HDRS))
|
||||
CTL_CHECKS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_CHECKS))
|
||||
CTL_OBJS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_OBJS))
|
||||
$(CTL_OBJS): $(BUILD_FILES) ctl/BUILD.mk
|
||||
|
||||
.PHONY: o/$(MODE)/ctl
|
||||
o/$(MODE)/ctl: $(CTL_CHECKS)
|
||||
+5015
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,28 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ACCUMULATE_H_
|
||||
#define CTL_ACCUMULATE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class T>
|
||||
constexpr T
|
||||
accumulate(InputIt first, InputIt last, T init)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
init = init + *first;
|
||||
return init;
|
||||
}
|
||||
|
||||
template<class InputIt, class T, class BinaryOperation>
|
||||
constexpr T
|
||||
accumulate(InputIt first, InputIt last, T init, BinaryOperation op)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
init = op(init, *first);
|
||||
return init;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ACCUMULATE_H_
|
||||
@@ -0,0 +1,55 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADD_LVALUE_REFERENCE_H_
|
||||
#define CTL_ADD_LVALUE_REFERENCE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct add_lvalue_reference
|
||||
{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct add_lvalue_reference<T&>
|
||||
{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct add_lvalue_reference<T&&>
|
||||
{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<void>
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<const void>
|
||||
{
|
||||
typedef const void type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<volatile void>
|
||||
{
|
||||
typedef volatile void type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct add_lvalue_reference<const volatile void>
|
||||
{
|
||||
typedef const volatile void type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADD_LVALUE_REFERENCE_H_
|
||||
@@ -0,0 +1,43 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADD_POINTER_H_
|
||||
#define CTL_ADD_POINTER_H_
|
||||
#include "remove_reference.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
// Primary template
|
||||
template<typename T>
|
||||
struct add_pointer
|
||||
{
|
||||
typedef typename remove_reference<T>::type* type;
|
||||
};
|
||||
|
||||
// Specialization for functions
|
||||
template<typename R, typename... Args>
|
||||
struct add_pointer<R(Args...)>
|
||||
{
|
||||
typedef R (*type)(Args...);
|
||||
};
|
||||
|
||||
// Specialization for function references
|
||||
template<typename R, typename... Args>
|
||||
struct add_pointer<R (&)(Args...)>
|
||||
{
|
||||
typedef R (*type)(Args...);
|
||||
};
|
||||
|
||||
// Specialization for rvalue references to functions
|
||||
template<typename R, typename... Args>
|
||||
struct add_pointer<R (&&)(Args...)>
|
||||
{
|
||||
typedef R (*type)(Args...);
|
||||
};
|
||||
|
||||
// Helper alias template (C++14 and later)
|
||||
template<typename T>
|
||||
using add_pointer_t = typename add_pointer<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADD_POINTER_H_
|
||||
@@ -0,0 +1,29 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADDRESSOF_H_
|
||||
#define CTL_ADDRESSOF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
T*
|
||||
addressof(T& arg) noexcept
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
&const_cast<char&>(reinterpret_cast<const volatile char&>(arg)));
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
R (*addressof(R (*&arg)(Args...)) noexcept)
|
||||
(Args...)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T*
|
||||
addressof(T&&) = delete;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADDRESSOF_H_
|
||||
@@ -0,0 +1,24 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ADVANCE_H_
|
||||
#define CTL_ADVANCE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class Distance>
|
||||
constexpr void
|
||||
advance(InputIt& it, Distance n)
|
||||
{
|
||||
while (n > 0) {
|
||||
--n;
|
||||
++it;
|
||||
}
|
||||
while (n < 0) {
|
||||
++n;
|
||||
--it;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ADVANCE_H_
|
||||
@@ -0,0 +1,20 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ALL_OF_H_
|
||||
#define CTL_ALL_OF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class UnaryPredicate>
|
||||
constexpr bool
|
||||
all_of(InputIt first, InputIt last, UnaryPredicate p)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (!p(*first))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ALL_OF_H_
|
||||
@@ -0,0 +1,94 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ALLOCATOR_H_
|
||||
#define CTL_ALLOCATOR_H_
|
||||
#include "bad_alloc.h"
|
||||
#include "integral_constant.h"
|
||||
#include "new.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using propagate_on_container_move_assignment = ctl::true_type;
|
||||
using is_always_equal = ctl::true_type;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
constexpr allocator() noexcept = default;
|
||||
|
||||
constexpr allocator(const allocator&) noexcept = default;
|
||||
|
||||
template<class U>
|
||||
constexpr allocator(const allocator<U>&) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ~allocator() = default;
|
||||
|
||||
[[nodiscard]] T* allocate(size_type n)
|
||||
{
|
||||
if (n > __SIZE_MAX__ / sizeof(T))
|
||||
throw ctl::bad_alloc();
|
||||
if (auto p = static_cast<T*>(::operator new(
|
||||
n * sizeof(T), ctl::align_val_t(alignof(T)), ctl::nothrow)))
|
||||
return p;
|
||||
throw ctl::bad_alloc();
|
||||
}
|
||||
|
||||
void deallocate(T* p, size_type n) noexcept
|
||||
{
|
||||
::operator delete(p, n * sizeof(T), ctl::align_val_t(alignof(T)));
|
||||
}
|
||||
|
||||
template<typename U, typename... Args>
|
||||
void construct(U* p, Args&&... args)
|
||||
{
|
||||
::new (static_cast<void*>(p)) U(ctl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void destroy(U* p)
|
||||
{
|
||||
p->~U();
|
||||
}
|
||||
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
return __SIZE_MAX__ / sizeof(T);
|
||||
}
|
||||
|
||||
allocator& operator=(const allocator&) = default;
|
||||
|
||||
template<typename U>
|
||||
struct rebind
|
||||
{
|
||||
using other = allocator<U>;
|
||||
};
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
bool
|
||||
operator==(const allocator<T>&, const allocator<U>&) noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
bool
|
||||
operator!=(const allocator<T>&, const allocator<U>&) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ALLOCATOR_H_
|
||||
@@ -0,0 +1,74 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ALLOCATOR_TRAITS_H_
|
||||
#define CTL_ALLOCATOR_TRAITS_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Alloc>
|
||||
struct allocator_traits
|
||||
{
|
||||
using allocator_type = Alloc;
|
||||
using value_type = typename Alloc::value_type;
|
||||
using pointer = typename Alloc::pointer;
|
||||
using const_pointer = typename Alloc::const_pointer;
|
||||
using void_pointer = void*;
|
||||
using const_void_pointer = const void*;
|
||||
using difference_type = typename Alloc::difference_type;
|
||||
using size_type = typename Alloc::size_type;
|
||||
|
||||
using propagate_on_container_copy_assignment = false_type;
|
||||
using propagate_on_container_move_assignment = true_type;
|
||||
using propagate_on_container_swap = false_type;
|
||||
using is_always_equal = true_type;
|
||||
|
||||
template<typename T>
|
||||
using rebind_alloc = typename Alloc::template rebind<T>::other;
|
||||
|
||||
template<typename T>
|
||||
using rebind_traits = allocator_traits<rebind_alloc<T>>;
|
||||
|
||||
__attribute__((__always_inline__)) static pointer allocate(Alloc& a,
|
||||
size_type n)
|
||||
{
|
||||
return a.allocate(n);
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static void deallocate(Alloc& a,
|
||||
pointer p,
|
||||
size_type n)
|
||||
{
|
||||
a.deallocate(p, n);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
__attribute__((__always_inline__)) static void construct(Alloc& a,
|
||||
T* p,
|
||||
Args&&... args)
|
||||
{
|
||||
::new ((void*)p) T(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
__attribute__((__always_inline__)) static void destroy(Alloc& a, T* p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static size_type max_size(
|
||||
const Alloc& a) noexcept
|
||||
{
|
||||
return __PTRDIFF_MAX__ / sizeof(value_type);
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static Alloc
|
||||
select_on_container_copy_construction(const Alloc& a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ALLOCATOR_TRAITS_H_
|
||||
@@ -0,0 +1,20 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ANY_OF_H_
|
||||
#define CTL_ANY_OF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class UnaryPredicate>
|
||||
constexpr bool
|
||||
any_of(InputIt first, InputIt last, UnaryPredicate p)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (p(*first))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ANY_OF_H_
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ARRAY_H_
|
||||
#define CTL_ARRAY_H_
|
||||
#include "initializer_list.h"
|
||||
#include "out_of_range.h"
|
||||
#include "reverse_iterator.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct array
|
||||
{
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
using reverse_iterator = ctl::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
|
||||
|
||||
T elems[N];
|
||||
|
||||
constexpr array() = default;
|
||||
|
||||
constexpr array(std::initializer_list<T> init)
|
||||
{
|
||||
auto it = init.begin();
|
||||
for (size_t i = 0; i < N && it != init.end(); ++i, ++it)
|
||||
elems[i] = *it;
|
||||
}
|
||||
|
||||
constexpr reference at(size_type pos)
|
||||
{
|
||||
if (pos >= N)
|
||||
throw ctl::out_of_range("out of range");
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= N)
|
||||
throw ctl::out_of_range("out of range");
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr reference operator[](size_type pos)
|
||||
{
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference operator[](size_type pos) const
|
||||
{
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr reference front()
|
||||
{
|
||||
return elems[0];
|
||||
}
|
||||
|
||||
constexpr const_reference front() const
|
||||
{
|
||||
return elems[0];
|
||||
}
|
||||
|
||||
constexpr reference back()
|
||||
{
|
||||
return elems[N - 1];
|
||||
}
|
||||
|
||||
constexpr const_reference back() const
|
||||
{
|
||||
return elems[N - 1];
|
||||
}
|
||||
|
||||
constexpr T* data() noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr const T* data() const noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr iterator begin() noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const noexcept
|
||||
{
|
||||
return elems;
|
||||
}
|
||||
|
||||
constexpr iterator end() noexcept
|
||||
{
|
||||
return elems + N;
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const noexcept
|
||||
{
|
||||
return elems + N;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rbegin() noexcept
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rend() noexcept
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const noexcept
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crbegin() const noexcept
|
||||
{
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crend() const noexcept
|
||||
{
|
||||
return rend();
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept
|
||||
{
|
||||
return N == 0;
|
||||
}
|
||||
|
||||
constexpr size_type size() const noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
constexpr size_type max_size() const noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
void fill(const T& value)
|
||||
{
|
||||
for (size_type i = 0; i < N; ++i) {
|
||||
elems[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void swap(array& other) noexcept
|
||||
{
|
||||
for (size_type i = 0; i < N; ++i) {
|
||||
T temp = elems[i];
|
||||
elems[i] = other.elems[i];
|
||||
other.elems[i] = temp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator==(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (!(lhs[i] == rhs[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator!=(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator<(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (lhs[i] < rhs[i])
|
||||
return true;
|
||||
if (rhs[i] < lhs[i])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator<=(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator>(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool
|
||||
operator>=(const array<T, N>& lhs, const array<T, N>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
void
|
||||
swap(array<T, N>& lhs, array<T, N>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ARRAY_H_
|
||||
@@ -0,0 +1,64 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_BACK_INSERTER_H_
|
||||
#define CTL_BACK_INSERTER_H_
|
||||
#include "iterator.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class Container>
|
||||
class back_insert_iterator
|
||||
{
|
||||
protected:
|
||||
Container* container;
|
||||
|
||||
public:
|
||||
using iterator_category = ctl::output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = void;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
|
||||
explicit back_insert_iterator(Container& c) : container(&c)
|
||||
{
|
||||
}
|
||||
|
||||
back_insert_iterator& operator=(const typename Container::value_type& value)
|
||||
{
|
||||
container->push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator& operator=(typename Container::value_type&& value)
|
||||
{
|
||||
container->push_back(ctl::move(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator& operator*()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator& operator++()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
back_insert_iterator operator++(int)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Container>
|
||||
back_insert_iterator<Container>
|
||||
back_inserter(Container& c)
|
||||
{
|
||||
return back_insert_iterator<Container>(c);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_BACK_INSERTER_H_
|
||||
@@ -0,0 +1,23 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_BAD_ALLOC_H_
|
||||
#define CTL_BAD_ALLOC_H_
|
||||
#include "exception.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class bad_alloc : public exception
|
||||
{
|
||||
public:
|
||||
bad_alloc() noexcept = default;
|
||||
~bad_alloc() override = default;
|
||||
|
||||
const char* what() const noexcept override
|
||||
{
|
||||
return "ctl::bad_alloc";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_BAD_ALLOC_H_
|
||||
@@ -0,0 +1,22 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_CONDITIONAL_H_
|
||||
#define CTL_CONDITIONAL_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<bool B, class T, class F>
|
||||
struct conditional
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T, class F>
|
||||
struct conditional<false, T, F>
|
||||
{
|
||||
typedef F type;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_CONDITIONAL_H_
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_COPY_H_
|
||||
#define CTL_COPY_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt, class OutputIt>
|
||||
OutputIt
|
||||
copy(InputIt first, InputIt last, OutputIt d_first)
|
||||
{
|
||||
while (first != last) {
|
||||
*d_first = *first;
|
||||
++d_first;
|
||||
++first;
|
||||
}
|
||||
return d_first;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_COPY_H_
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_DECAY_H_
|
||||
#define CTL_DECAY_H_
|
||||
#include "add_pointer.h"
|
||||
#include "conditional.h"
|
||||
#include "is_array.h"
|
||||
#include "is_function.h"
|
||||
#include "remove_cv.h"
|
||||
#include "remove_extent.h"
|
||||
#include "remove_reference.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct decay
|
||||
{
|
||||
private:
|
||||
typedef typename remove_reference<T>::type U;
|
||||
|
||||
public:
|
||||
typedef typename conditional<
|
||||
is_array<U>::value,
|
||||
typename remove_extent<U>::type*,
|
||||
typename conditional<is_function<U>::value,
|
||||
typename add_pointer<U>::type,
|
||||
typename remove_cv<U>::type>::type>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using decay_t = typename decay<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_DECAY_H_
|
||||
@@ -0,0 +1,44 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_DEFAULT_DELETE_H_
|
||||
#define CTL_DEFAULT_DELETE_H_
|
||||
#include "enable_if.h"
|
||||
#include "is_convertible.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct default_delete
|
||||
{
|
||||
constexpr default_delete() noexcept = default;
|
||||
template<typename U,
|
||||
typename = typename ctl::enable_if<
|
||||
ctl::is_convertible<U*, T*>::value>::type>
|
||||
constexpr default_delete(const default_delete<U>&) noexcept
|
||||
{
|
||||
}
|
||||
constexpr void operator()(T* const p) const noexcept
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct default_delete<T[]>
|
||||
{
|
||||
constexpr default_delete() noexcept = default;
|
||||
template<typename U,
|
||||
typename = typename ctl::enable_if<
|
||||
ctl::is_convertible<U (*)[], T (*)[]>::value>::type>
|
||||
constexpr default_delete(const default_delete<U[]>&) noexcept
|
||||
{
|
||||
}
|
||||
constexpr void operator()(T* const p) const noexcept
|
||||
{
|
||||
delete[] p;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_DEFAULT_DELETE_H_
|
||||
@@ -0,0 +1,37 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_DISTANCE_H_
|
||||
#define CTL_DISTANCE_H_
|
||||
#include "iterator.h"
|
||||
#include "iterator_traits.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIter>
|
||||
constexpr typename iterator_traits<InputIter>::difference_type
|
||||
distance_impl(InputIter first, InputIter last, input_iterator_tag)
|
||||
{
|
||||
typename iterator_traits<InputIter>::difference_type res(0);
|
||||
for (; first != last; ++first)
|
||||
++res;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class RandIter>
|
||||
constexpr typename iterator_traits<RandIter>::difference_type
|
||||
distance_impl(RandIter first, RandIter last, random_access_iterator_tag)
|
||||
{
|
||||
return last - first;
|
||||
}
|
||||
|
||||
template<class InputIter>
|
||||
constexpr typename iterator_traits<InputIter>::difference_type
|
||||
distance(InputIter first, InputIter last)
|
||||
{
|
||||
return distance_impl(
|
||||
first, last, typename iterator_traits<InputIter>::iterator_category());
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_DISTANCE_H_
|
||||
@@ -0,0 +1,23 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ENABLE_IF_H_
|
||||
#define CTL_ENABLE_IF_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<bool B, class T = void>
|
||||
struct enable_if
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
struct enable_if<true, T>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<bool B, class T = void>
|
||||
using enable_if_t = typename enable_if<B, T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ENABLE_IF_H_
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_EQUAL_H_
|
||||
#define CTL_EQUAL_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
bool
|
||||
equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) {
|
||||
if (!(*first1 == *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overload that takes a predicate
|
||||
template<class InputIt1, class InputIt2, class BinaryPredicate>
|
||||
bool
|
||||
equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPredicate pred)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) {
|
||||
if (!pred(*first1, *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overloads that take two ranges (C++14 and later)
|
||||
template<class InputIt1, class InputIt2>
|
||||
bool
|
||||
equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
|
||||
{
|
||||
for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
|
||||
if (!(*first1 == *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return first1 == last1 && first2 == last2;
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2, class BinaryPredicate>
|
||||
bool
|
||||
equal(InputIt1 first1,
|
||||
InputIt1 last1,
|
||||
InputIt2 first2,
|
||||
InputIt2 last2,
|
||||
BinaryPredicate pred)
|
||||
{
|
||||
for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
|
||||
if (!pred(*first1, *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return first1 == last1 && first2 == last2;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_EQUAL_H_ */
|
||||
@@ -0,0 +1,22 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_EXCEPTION_H_
|
||||
#define CTL_EXCEPTION_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class exception
|
||||
{
|
||||
public:
|
||||
exception() noexcept = default;
|
||||
virtual ~exception() = default;
|
||||
|
||||
virtual const char* what() const noexcept
|
||||
{
|
||||
return "ctl::exception";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_EXCEPTION_H_
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_FILL_H_
|
||||
#define CTL_FILL_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename ForwardIt, typename T>
|
||||
void
|
||||
fill(ForwardIt first, ForwardIt last, const T& value)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
*first = value;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_FILL_H_
|
||||
@@ -0,0 +1,19 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_FILL_N_H_
|
||||
#define CTL_FILL_N_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename OutputIt, typename Size, typename T>
|
||||
OutputIt
|
||||
fill_n(OutputIt first, Size count, const T& value)
|
||||
{
|
||||
for (; count > 0; --count, ++first)
|
||||
*first = value;
|
||||
return first;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_FILL_N_H_
|
||||
@@ -0,0 +1,64 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef _LIBCPP_INITIALIZER_LIST
|
||||
#define _LIBCPP_INITIALIZER_LIST
|
||||
|
||||
namespace std {
|
||||
|
||||
template<class T>
|
||||
class initializer_list
|
||||
{
|
||||
constexpr initializer_list(const T* b, size_t s) noexcept
|
||||
: begin_(b), size_(s)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef const T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef size_t size_type;
|
||||
typedef const T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
constexpr initializer_list() noexcept : begin_(nullptr), size_(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
constexpr const T* begin() const noexcept
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
|
||||
constexpr const T* end() const noexcept
|
||||
{
|
||||
return begin_ + size_;
|
||||
}
|
||||
|
||||
private:
|
||||
const T* begin_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline constexpr const T*
|
||||
begin(initializer_list<T> i) noexcept
|
||||
{
|
||||
return i.begin();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline constexpr const T*
|
||||
end(initializer_list<T> i) noexcept
|
||||
{
|
||||
return i.end();
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // _LIBCPP_INITIALIZER_LIST
|
||||
@@ -0,0 +1,29 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_INTEGRAL_CONSTANT_H_
|
||||
#define CTL_INTEGRAL_CONSTANT_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class T, T v>
|
||||
struct integral_constant
|
||||
{
|
||||
static constexpr T value = v;
|
||||
typedef T value_type;
|
||||
typedef integral_constant type;
|
||||
constexpr operator value_type() const noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
constexpr value_type operator()() const noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_INTEGRAL_CONSTANT_H_
|
||||
@@ -0,0 +1,26 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_ARRAY_H_
|
||||
#define CTL_IS_ARRAY_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_array : false_type
|
||||
{};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct is_array<T[N]> : true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_array<T[]> : true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_array_v = is_array<T>::value;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_ARRAY_H_
|
||||
@@ -0,0 +1,54 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_CONVERTIBLE_H_
|
||||
#define CTL_IS_CONVERTIBLE_H_
|
||||
|
||||
#include "ctl/integral_constant.h"
|
||||
#include "ctl/void_t.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
// Declaration of declval
|
||||
template<typename T>
|
||||
T&&
|
||||
declval() noexcept;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename From, typename To, typename = void>
|
||||
struct is_convertible_impl : false_type
|
||||
{};
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_convertible_impl<From,
|
||||
To,
|
||||
void_t<decltype(static_cast<To>(declval<From>()))>>
|
||||
: true_type
|
||||
{};
|
||||
|
||||
// Handle void types separately
|
||||
template<>
|
||||
struct is_convertible_impl<void, void> : true_type
|
||||
{};
|
||||
|
||||
template<typename To>
|
||||
struct is_convertible_impl<void, To> : false_type
|
||||
{};
|
||||
|
||||
template<typename From>
|
||||
struct is_convertible_impl<From, void> : false_type
|
||||
{};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_convertible : detail::is_convertible_impl<From, To>
|
||||
{};
|
||||
|
||||
// Helper variable template (C++17 and later)
|
||||
template<typename From, typename To>
|
||||
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_CONVERTIBLE_H_
|
||||
@@ -0,0 +1,120 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_FUNCTION_H_
|
||||
#define CTL_IS_FUNCTION_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
// Primary template
|
||||
template<class>
|
||||
struct is_function : false_type
|
||||
{};
|
||||
|
||||
// Specializations for various function types
|
||||
|
||||
// Regular functions
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...)> : true_type
|
||||
{};
|
||||
|
||||
// Functions with cv-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile> : true_type
|
||||
{};
|
||||
|
||||
// Functions with ref-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...)&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) &&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const&&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile&&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile&&> : true_type
|
||||
{};
|
||||
|
||||
// Variadic functions
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...)> : true_type
|
||||
{};
|
||||
|
||||
// Variadic functions with cv-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile> : true_type
|
||||
{};
|
||||
|
||||
// Variadic functions with ref-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...)&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) &&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const&&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile&&> : true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile&&> : true_type
|
||||
{};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_FUNCTION_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_INTEGRAL_H_
|
||||
#define CTL_IS_INTEGRAL_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_integral : false_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<bool> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<signed char> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned char> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<short> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned short> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<int> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned int> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<long> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned long> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<long long> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned long long> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char16_t> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char32_t> : true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<wchar_t> : true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_integral_v = is_integral<T>::value;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_INTEGRAL_H_
|
||||
@@ -0,0 +1,35 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_REFERENCE_H_
|
||||
#define CTL_IS_REFERENCE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
// Primary template
|
||||
template<class T>
|
||||
struct is_reference
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
// Specialization for lvalue reference
|
||||
template<class T>
|
||||
struct is_reference<T&>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
// Specialization for rvalue reference
|
||||
template<class T>
|
||||
struct is_reference<T&&>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
// Helper variable template (C++14 and later)
|
||||
template<class T>
|
||||
inline constexpr bool is_reference_v = is_reference<T>::value;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_REFERENCE_H_
|
||||
@@ -0,0 +1,25 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_SAME_H_
|
||||
#define CTL_IS_SAME_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T, typename U>
|
||||
struct is_same
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
inline constexpr bool is_same_v = is_same<T, U>::value;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_SAME_H_
|
||||
@@ -0,0 +1,16 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_SIGNED_H_
|
||||
#define CTL_IS_SIGNED_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_signed
|
||||
{
|
||||
static constexpr bool value = T(0) > T(-1);
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_SIGNED_H_
|
||||
@@ -0,0 +1,25 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_SORTED_H_
|
||||
#define CTL_IS_SORTED_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename It, typename Compare>
|
||||
bool
|
||||
is_sorted(It first, It last, Compare comp)
|
||||
{
|
||||
if (first == last)
|
||||
return true;
|
||||
It next = first;
|
||||
while (++next != last) {
|
||||
if (comp(*next, *first))
|
||||
return false;
|
||||
first = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_SORTED_H_
|
||||
@@ -0,0 +1,16 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_UNSIGNED_H_
|
||||
#define CTL_IS_UNSIGNED_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_unsigned
|
||||
{
|
||||
static constexpr bool value = T(0) < T(-1);
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_UNSIGNED_H_
|
||||
@@ -0,0 +1,28 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_OUTPUT_ITERATOR_TAG_H_
|
||||
#define CTL_OUTPUT_ITERATOR_TAG_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
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
|
||||
{};
|
||||
|
||||
struct contiguous_iterator_tag : public random_access_iterator_tag
|
||||
{};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_OUTPUT_ITERATOR_TAG_H_
|
||||
@@ -0,0 +1,31 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ITERATOR_TRAITS_H_
|
||||
#define CTL_ITERATOR_TRAITS_H_
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class Iterator>
|
||||
struct iterator_traits
|
||||
{
|
||||
using iterator_category = typename Iterator::iterator_category;
|
||||
using value_type = typename Iterator::value_type;
|
||||
using difference_type = typename Iterator::difference_type;
|
||||
using pointer = typename Iterator::pointer;
|
||||
using reference = typename Iterator::reference;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct iterator_traits<T*>
|
||||
{
|
||||
using iterator_category = void*; // We don't actually use this
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ITERATOR_TRAITS_H_
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_LESS_H_
|
||||
#define CTL_LESS_H_
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class T = void>
|
||||
struct less
|
||||
{
|
||||
constexpr bool operator()(const T& lhs, const T& rhs) const
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
typedef T first_argument_type;
|
||||
typedef T second_argument_type;
|
||||
typedef bool result_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct less<void>
|
||||
{
|
||||
template<class T, class U>
|
||||
constexpr auto operator()(T&& lhs,
|
||||
U&& rhs) const -> decltype(ctl::forward<T>(lhs) <
|
||||
ctl::forward<U>(rhs))
|
||||
{
|
||||
return ctl::forward<T>(lhs) < ctl::forward<U>(rhs);
|
||||
}
|
||||
|
||||
typedef void is_transparent;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_LESS_H_ */
|
||||
@@ -0,0 +1,43 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_LEXICOGRAPHICAL_COMPARE_H_
|
||||
#define CTL_LEXICOGRAPHICAL_COMPARE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
bool
|
||||
lexicographical_compare(InputIt1 first1,
|
||||
InputIt1 last1,
|
||||
InputIt2 first2,
|
||||
InputIt2 last2)
|
||||
{
|
||||
for (; (first1 != last1) && (first2 != last2); ++first1, ++first2) {
|
||||
if (*first1 < *first2)
|
||||
return true;
|
||||
if (*first2 < *first1)
|
||||
return false;
|
||||
}
|
||||
return (first1 == last1) && (first2 != last2);
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2, class Compare>
|
||||
bool
|
||||
lexicographical_compare(InputIt1 first1,
|
||||
InputIt1 last1,
|
||||
InputIt2 first2,
|
||||
InputIt2 last2,
|
||||
Compare 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);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_LEXICOGRAPHICAL_COMPARE_H_ */
|
||||
@@ -0,0 +1,353 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_MAP_H_
|
||||
#define CTL_MAP_H_
|
||||
#include "out_of_range.h"
|
||||
#include "set.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Key, typename Value, typename Compare = ctl::less<Key>>
|
||||
class map
|
||||
{
|
||||
class EntryCompare
|
||||
{
|
||||
public:
|
||||
explicit EntryCompare(Compare comp = Compare()) : comp_(comp)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(const ctl::pair<const Key, Value>& lhs,
|
||||
const ctl::pair<const Key, Value>& rhs) const
|
||||
{
|
||||
return comp_(lhs.first, rhs.first);
|
||||
}
|
||||
|
||||
private:
|
||||
Compare comp_;
|
||||
};
|
||||
|
||||
ctl::set<ctl::pair<const Key, Value>, EntryCompare> data_;
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = ctl::pair<const Key, Value>;
|
||||
using size_type = typename ctl::set<value_type, EntryCompare>::size_type;
|
||||
using difference_type =
|
||||
typename ctl::set<value_type, EntryCompare>::difference_type;
|
||||
using key_compare = Compare;
|
||||
using value_compare = EntryCompare;
|
||||
using iterator = typename ctl::set<value_type, EntryCompare>::iterator;
|
||||
using const_iterator =
|
||||
typename ctl::set<value_type, EntryCompare>::const_iterator;
|
||||
using reverse_iterator =
|
||||
typename ctl::set<value_type, EntryCompare>::reverse_iterator;
|
||||
using const_reverse_iterator =
|
||||
typename ctl::set<value_type, EntryCompare>::const_reverse_iterator;
|
||||
|
||||
map() : data_(EntryCompare())
|
||||
{
|
||||
}
|
||||
|
||||
explicit map(const Compare& comp) : data_(EntryCompare(comp))
|
||||
{
|
||||
}
|
||||
|
||||
map(const map& other) = default;
|
||||
map(map&& other) noexcept = default;
|
||||
map(std::initializer_list<value_type> init, const Compare& comp = Compare())
|
||||
: data_(init, EntryCompare(comp))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename InputIt>
|
||||
map(InputIt first, InputIt last, const Compare& comp = Compare())
|
||||
: data_(first, last, EntryCompare(comp))
|
||||
{
|
||||
}
|
||||
|
||||
map& operator=(const map& other) = default;
|
||||
map& operator=(map&& other) noexcept = default;
|
||||
map& operator=(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
data_ = ilist;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() noexcept
|
||||
{
|
||||
return data_.begin();
|
||||
}
|
||||
|
||||
const_iterator begin() const noexcept
|
||||
{
|
||||
return data_.begin();
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept
|
||||
{
|
||||
return data_.cbegin();
|
||||
}
|
||||
|
||||
iterator end() noexcept
|
||||
{
|
||||
return data_.end();
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept
|
||||
{
|
||||
return data_.end();
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept
|
||||
{
|
||||
return data_.cend();
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() noexcept
|
||||
{
|
||||
return data_.rbegin();
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return data_.rbegin();
|
||||
}
|
||||
|
||||
const_reverse_iterator crbegin() const noexcept
|
||||
{
|
||||
return data_.crbegin();
|
||||
}
|
||||
|
||||
reverse_iterator rend() noexcept
|
||||
{
|
||||
return data_.rend();
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const noexcept
|
||||
{
|
||||
return data_.rend();
|
||||
}
|
||||
|
||||
const_reverse_iterator crend() const noexcept
|
||||
{
|
||||
return data_.crend();
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
size_type size() const noexcept
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
return data_.max_size();
|
||||
}
|
||||
|
||||
Value& operator[](const Key& key)
|
||||
{
|
||||
return ((data_.insert(make_pair(key, Value()))).first)->second;
|
||||
}
|
||||
|
||||
Value& operator[](Key&& key)
|
||||
{
|
||||
return ((data_.insert(make_pair(ctl::move(key), Value()))).first)
|
||||
->second;
|
||||
}
|
||||
|
||||
Value& at(const Key& key)
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
throw ctl::out_of_range("out of range");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const Value& at(const Key& key) const
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
throw ctl::out_of_range("out of range");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ctl::pair<iterator, bool> insert(const value_type& value)
|
||||
{
|
||||
return data_.insert(value);
|
||||
}
|
||||
|
||||
ctl::pair<iterator, bool> insert(value_type&& value)
|
||||
{
|
||||
return data_.insert(ctl::move(value));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
ctl::pair<iterator, bool> insert(P&& value)
|
||||
{
|
||||
return data_.insert(value_type(ctl::forward<P>(value)));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value)
|
||||
{
|
||||
return data_.insert(hint, value);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value)
|
||||
{
|
||||
return data_.insert(hint, ctl::move(value));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
iterator insert(const_iterator hint, P&& value)
|
||||
{
|
||||
return data_.insert(hint, value_type(ctl::forward<P>(value)));
|
||||
}
|
||||
|
||||
template<typename InputIt>
|
||||
void insert(InputIt first, InputIt last)
|
||||
{
|
||||
data_.insert(first, last);
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
data_.insert(ilist);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
ctl::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return data_.emplace(ctl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
iterator emplace_hint(const_iterator hint, Args&&... args)
|
||||
{
|
||||
return data_.emplace_hint(hint, ctl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator pos)
|
||||
{
|
||||
return data_.erase(pos);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
return data_.erase(first, last);
|
||||
}
|
||||
|
||||
size_type erase(const Key& key)
|
||||
{
|
||||
return data_.erase(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
void swap(map& other) noexcept
|
||||
{
|
||||
data_.swap(other.data_);
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
data_.clear();
|
||||
}
|
||||
|
||||
iterator find(const Key& key)
|
||||
{
|
||||
return data_.find(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator find(const Key& key) const
|
||||
{
|
||||
return data_.find(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
size_type count(const Key& key) const
|
||||
{
|
||||
return data_.count(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
iterator lower_bound(const Key& key)
|
||||
{
|
||||
return data_.lower_bound(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const Key& key) const
|
||||
{
|
||||
return data_.lower_bound(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
iterator upper_bound(const Key& key)
|
||||
{
|
||||
return data_.upper_bound(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const Key& key) const
|
||||
{
|
||||
return data_.upper_bound(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
ctl::pair<iterator, iterator> equal_range(const Key& key)
|
||||
{
|
||||
return data_.equal_range(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
ctl::pair<const_iterator, const_iterator> equal_range(const Key& key) const
|
||||
{
|
||||
return data_.equal_range(make_pair(key, Value()));
|
||||
}
|
||||
|
||||
key_compare key_comp() const
|
||||
{
|
||||
return data_.value_comp().comp;
|
||||
}
|
||||
|
||||
value_compare value_comp() const
|
||||
{
|
||||
return data_.value_comp();
|
||||
}
|
||||
|
||||
friend bool operator==(const map& lhs, const map& rhs)
|
||||
{
|
||||
return lhs.data_ == rhs.data_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const map& lhs, const map& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
friend bool operator<(const map& lhs, const map& rhs)
|
||||
{
|
||||
return lhs.data_ < rhs.data_;
|
||||
}
|
||||
|
||||
friend bool operator<=(const map& lhs, const map& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
friend bool operator>(const map& lhs, const map& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
friend bool operator>=(const map& lhs, const map& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
friend void swap(map& lhs, map& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_MAP_H_
|
||||
@@ -0,0 +1,17 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_MAX_H_
|
||||
#define CTL_MAX_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class T>
|
||||
inline constexpr const T&
|
||||
max(const T& a, const T& b)
|
||||
{
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_MAX_H_ */
|
||||
@@ -0,0 +1,17 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_MIN_H_
|
||||
#define CTL_MIN_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class T>
|
||||
inline constexpr const T&
|
||||
min(const T& a, const T& b)
|
||||
{
|
||||
return b < a ? b : a;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_MIN_H_ */
|
||||
@@ -0,0 +1,20 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_MOVE_BACKWARD_H_
|
||||
#define CTL_MOVE_BACKWARD_H_
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename BidirIt1, typename BidirIt2>
|
||||
BidirIt2
|
||||
move_backward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last)
|
||||
{
|
||||
while (first != last)
|
||||
*(--d_last) = ctl::move(*(--last));
|
||||
return d_last;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_MOVE_BACKWARD_H_
|
||||
@@ -0,0 +1,172 @@
|
||||
#ifndef CTL_MOVE_ITERATOR_H_
|
||||
#define CTL_MOVE_ITERATOR_H_
|
||||
#include "iterator_traits.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Iterator>
|
||||
class move_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_type = Iterator;
|
||||
using iterator_category =
|
||||
typename ctl::iterator_traits<Iterator>::iterator_category;
|
||||
using value_type = typename ctl::iterator_traits<Iterator>::value_type;
|
||||
using difference_type =
|
||||
typename ctl::iterator_traits<Iterator>::difference_type;
|
||||
using pointer = Iterator;
|
||||
using reference = value_type&&;
|
||||
|
||||
constexpr move_iterator() : current()
|
||||
{
|
||||
}
|
||||
|
||||
explicit constexpr move_iterator(Iterator i) : current(i)
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
constexpr move_iterator(const move_iterator<U>& u) : current(u.base())
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Iterator base() const
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
constexpr reference operator*() const
|
||||
{
|
||||
return static_cast<reference>(*current);
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
constexpr move_iterator& operator++()
|
||||
{
|
||||
++current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr move_iterator operator++(int)
|
||||
{
|
||||
move_iterator tmp = *this;
|
||||
++current;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
constexpr move_iterator& operator--()
|
||||
{
|
||||
--current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr move_iterator operator--(int)
|
||||
{
|
||||
move_iterator tmp = *this;
|
||||
--current;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
constexpr move_iterator operator+(difference_type n) const
|
||||
{
|
||||
return move_iterator(current + n);
|
||||
}
|
||||
|
||||
constexpr move_iterator& operator+=(difference_type n)
|
||||
{
|
||||
current += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr move_iterator operator-(difference_type n) const
|
||||
{
|
||||
return move_iterator(current - n);
|
||||
}
|
||||
|
||||
constexpr move_iterator& operator-=(difference_type n)
|
||||
{
|
||||
current -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reference operator[](difference_type n) const
|
||||
{
|
||||
return ctl::move(current[n]);
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator current;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
__attribute__((__always_inline__)) constexpr move_iterator<Iterator>
|
||||
make_move_iterator(Iterator i)
|
||||
{
|
||||
return move_iterator<Iterator>(i);
|
||||
}
|
||||
|
||||
template<typename Iterator1, typename Iterator2>
|
||||
constexpr bool
|
||||
operator==(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
|
||||
{
|
||||
return x.base() == y.base();
|
||||
}
|
||||
|
||||
template<typename Iterator1, typename Iterator2>
|
||||
constexpr bool
|
||||
operator!=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
template<typename Iterator1, typename Iterator2>
|
||||
constexpr bool
|
||||
operator<(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
|
||||
{
|
||||
return x.base() < y.base();
|
||||
}
|
||||
|
||||
template<typename Iterator1, typename Iterator2>
|
||||
constexpr bool
|
||||
operator<=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
|
||||
{
|
||||
return !(y < x);
|
||||
}
|
||||
|
||||
template<typename Iterator1, typename Iterator2>
|
||||
constexpr bool
|
||||
operator>(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
|
||||
{
|
||||
return y < x;
|
||||
}
|
||||
|
||||
template<typename Iterator1, typename Iterator2>
|
||||
constexpr bool
|
||||
operator>=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
|
||||
{
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
constexpr move_iterator<Iterator>
|
||||
operator+(typename move_iterator<Iterator>::difference_type n,
|
||||
const move_iterator<Iterator>& x)
|
||||
{
|
||||
return x + n;
|
||||
}
|
||||
|
||||
template<typename Iterator1, typename Iterator2>
|
||||
constexpr auto
|
||||
operator-(const move_iterator<Iterator1>& x,
|
||||
const move_iterator<Iterator2>& y) -> decltype(x.base() - y.base())
|
||||
{
|
||||
return x.base() - y.base();
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_MOVE_ITERATOR_H_
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_MUTEX_H_
|
||||
#define CTL_MUTEX_H_
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
pthread_mutex_init(&m_, nullptr);
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&m_);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return pthread_mutex_trylock(&m_) == 0;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_);
|
||||
}
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
mutex(const mutex&) = delete;
|
||||
mutex& operator=(const mutex&) = delete;
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_MUTEX_H_
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "new.h"
|
||||
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
static void*
|
||||
_ctl_alloc(size_t n, size_t a) noexcept
|
||||
{
|
||||
void* p;
|
||||
if (!(p = memalign(a, n)))
|
||||
__builtin_trap();
|
||||
return p;
|
||||
}
|
||||
|
||||
static void*
|
||||
_ctl_alloc_nothrow(size_t n, size_t a, const ctl::nothrow_t&)
|
||||
{
|
||||
void* p;
|
||||
if (!(p = memalign(a, n)))
|
||||
__builtin_trap();
|
||||
return p;
|
||||
}
|
||||
|
||||
static void*
|
||||
_ctl_alloc1(size_t n) noexcept
|
||||
{
|
||||
void* p;
|
||||
if (!(p = malloc(n)))
|
||||
__builtin_trap();
|
||||
return p;
|
||||
}
|
||||
|
||||
static void*
|
||||
_ctl_alloc1_nothrow(size_t n, const ctl::nothrow_t&) noexcept
|
||||
{
|
||||
void* p;
|
||||
if (!(p = malloc(n)))
|
||||
__builtin_trap();
|
||||
return p;
|
||||
}
|
||||
|
||||
static void*
|
||||
_ctl_ret(size_t, void* p) noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
_ctl_free(void* p) noexcept
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
static void
|
||||
_ctl_nop(void*, void*) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
#undef __weak_reference
|
||||
#define __weak_reference(P, A) P __attribute__((weak, alias(#A)))
|
||||
|
||||
/* The ISO says that these should be replaceable by user code. It also says
|
||||
that the declarations for the first four (i.e. non placement-) operators
|
||||
new are implicitly available in each translation unit, including the std
|
||||
align_val_t parameter. (?) However, <new> also _defines_ the align_val_t
|
||||
type so you can’t just write your own. Our way through this morass is to
|
||||
supply ours as ctl::align_val_t and not implicitly declare anything, for
|
||||
now. If you have any brain cells left after reading this comment then go
|
||||
look at the eight operator delete weak references to free in the below. */
|
||||
|
||||
__weak_reference(void*
|
||||
operator new(size_t, ctl::align_val_t),
|
||||
_ctl_alloc);
|
||||
|
||||
__weak_reference(void*
|
||||
operator new(size_t,
|
||||
ctl::align_val_t,
|
||||
const ctl::nothrow_t&) noexcept,
|
||||
_ctl_alloc_nothrow);
|
||||
|
||||
__weak_reference(void*
|
||||
operator new[](size_t, ctl::align_val_t),
|
||||
_ctl_alloc);
|
||||
|
||||
__weak_reference(void*
|
||||
operator new[](size_t,
|
||||
ctl::align_val_t,
|
||||
const ctl::nothrow_t&) noexcept,
|
||||
_ctl_alloc_nothrow);
|
||||
|
||||
__weak_reference(void*
|
||||
operator new(size_t),
|
||||
_ctl_alloc1);
|
||||
|
||||
__weak_reference(void*
|
||||
operator new(size_t, const ctl::nothrow_t&) noexcept,
|
||||
_ctl_alloc1_nothrow);
|
||||
|
||||
__weak_reference(void*
|
||||
operator new[](size_t),
|
||||
_ctl_alloc1);
|
||||
|
||||
__weak_reference(void*
|
||||
operator new[](size_t, const ctl::nothrow_t&) noexcept,
|
||||
_ctl_alloc1_nothrow);
|
||||
|
||||
// XXX clang-format currently mutilates these for some reason.
|
||||
// clang-format off
|
||||
|
||||
__weak_reference(void* operator new(size_t, void*) noexcept, _ctl_ret);
|
||||
__weak_reference(void* operator new[](size_t, void*) noexcept, _ctl_ret);
|
||||
|
||||
__weak_reference(void operator delete(void*) noexcept, _ctl_free);
|
||||
__weak_reference(void operator delete[](void*) noexcept, _ctl_free);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wattribute-alias="
|
||||
__weak_reference(void operator delete(void*, ctl::align_val_t) noexcept,
|
||||
_ctl_free);
|
||||
__weak_reference(void operator delete[](void*, ctl::align_val_t) noexcept,
|
||||
_ctl_free);
|
||||
__weak_reference(void operator delete(void*, size_t) noexcept, _ctl_free);
|
||||
__weak_reference(void operator delete[](void*, size_t) noexcept, _ctl_free);
|
||||
__weak_reference(void operator delete(void*, size_t, ctl::align_val_t) noexcept,
|
||||
_ctl_free);
|
||||
__weak_reference(void operator delete[](void*, size_t, ctl::align_val_t)
|
||||
noexcept, _ctl_free);
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
__weak_reference(void operator delete(void*, void*) noexcept, _ctl_nop);
|
||||
__weak_reference(void operator delete[](void*, void*) noexcept, _ctl_nop);
|
||||
@@ -0,0 +1,50 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_NEW_H_
|
||||
#define COSMOPOLITAN_CTL_NEW_H_
|
||||
|
||||
#ifndef TINY
|
||||
__static_yoink("__demangle");
|
||||
#endif
|
||||
|
||||
namespace ctl {
|
||||
|
||||
enum class align_val_t : size_t
|
||||
{
|
||||
};
|
||||
|
||||
struct nothrow_t
|
||||
{
|
||||
explicit nothrow_t() = default;
|
||||
};
|
||||
|
||||
inline constexpr nothrow_t nothrow{};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
// XXX clang-format currently mutilates these for some reason.
|
||||
// clang-format off
|
||||
|
||||
void* operator new(size_t);
|
||||
void* operator new(size_t, const ctl::nothrow_t&) noexcept;
|
||||
void* operator new(size_t, ctl::align_val_t);
|
||||
void* operator new(size_t, ctl::align_val_t, const ctl::nothrow_t&) noexcept;
|
||||
|
||||
void* operator new[](size_t);
|
||||
void* operator new[](size_t, const ctl::nothrow_t&) noexcept;
|
||||
void* operator new[](size_t, ctl::align_val_t);
|
||||
void* operator new[](size_t, ctl::align_val_t, const ctl::nothrow_t&) noexcept;
|
||||
|
||||
void* operator new(size_t, void*) noexcept;
|
||||
void* operator new[](size_t, void*) noexcept;
|
||||
|
||||
void operator delete(void*) noexcept;
|
||||
void operator delete[](void*) noexcept;
|
||||
void operator delete(void*, ctl::align_val_t) noexcept;
|
||||
void operator delete[](void*, ctl::align_val_t) noexcept;
|
||||
void operator delete(void*, size_t) noexcept;
|
||||
void operator delete[](void*, size_t) noexcept;
|
||||
void operator delete(void*, size_t, ctl::align_val_t) noexcept;
|
||||
void operator delete[](void*, size_t, ctl::align_val_t) noexcept;
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_NEW_H_
|
||||
@@ -0,0 +1,123 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_NUMERIC_LIMITS_H_
|
||||
#define CTL_NUMERIC_LIMITS_H_
|
||||
#include "is_integral.h"
|
||||
#include "is_unsigned.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
class numeric_limits
|
||||
{
|
||||
static constexpr T max_signed()
|
||||
{
|
||||
return T(((uintmax_t)1 << (sizeof(T) * 8 - 1)) - 1);
|
||||
}
|
||||
|
||||
static constexpr T max_unsigned()
|
||||
{
|
||||
return T(~T(0));
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr bool is_specialized = ctl::is_integral<T>::value;
|
||||
static constexpr bool is_signed = !ctl::is_unsigned<T>::value;
|
||||
static constexpr bool is_integer = ctl::is_integral<T>::value;
|
||||
static constexpr bool is_exact = ctl::is_integral<T>::value;
|
||||
static constexpr int digits = sizeof(T) * 8 - (is_signed ? 1 : 0);
|
||||
|
||||
static constexpr T min() noexcept
|
||||
{
|
||||
return is_signed ? T(-max_signed() - 1) : T(0);
|
||||
}
|
||||
|
||||
static constexpr T max() noexcept
|
||||
{
|
||||
return is_signed ? max_signed() : max_unsigned();
|
||||
}
|
||||
|
||||
static constexpr T lowest() noexcept
|
||||
{
|
||||
return min();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct numeric_limits<bool>
|
||||
{
|
||||
static constexpr bool is_specialized = true;
|
||||
static constexpr bool is_signed = false;
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr bool is_exact = true;
|
||||
static constexpr int digits = 1;
|
||||
|
||||
static constexpr bool min() noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr bool max() noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr bool lowest() noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct numeric_limits<float>
|
||||
{
|
||||
static constexpr bool is_specialized = true;
|
||||
static constexpr bool is_signed = true;
|
||||
static constexpr bool is_integer = false;
|
||||
static constexpr bool is_exact = false;
|
||||
static constexpr int digits = 24;
|
||||
|
||||
static constexpr float min() noexcept
|
||||
{
|
||||
return __FLT_MIN__;
|
||||
}
|
||||
|
||||
static constexpr float max() noexcept
|
||||
{
|
||||
return __FLT_MAX__;
|
||||
}
|
||||
|
||||
static constexpr float lowest() noexcept
|
||||
{
|
||||
return -max();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct numeric_limits<double>
|
||||
{
|
||||
static constexpr bool is_specialized = true;
|
||||
static constexpr bool is_signed = true;
|
||||
static constexpr bool is_integer = false;
|
||||
static constexpr bool is_exact = false;
|
||||
static constexpr int digits = 53;
|
||||
|
||||
static constexpr double min() noexcept
|
||||
{
|
||||
return __DBL_MIN__;
|
||||
}
|
||||
|
||||
static constexpr double max() noexcept
|
||||
{
|
||||
return __DBL_MAX__;
|
||||
}
|
||||
|
||||
static constexpr double lowest() noexcept
|
||||
{
|
||||
return -max();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_NUMERIC_LIMITS_H_
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
#define COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
#include "new.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
class optional
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
~optional()
|
||||
{
|
||||
if (present_)
|
||||
value_.~T();
|
||||
}
|
||||
|
||||
optional() noexcept : present_(false)
|
||||
{
|
||||
}
|
||||
|
||||
optional(const T& value) : present_(true)
|
||||
{
|
||||
new (&value_) T(value);
|
||||
}
|
||||
|
||||
optional(T&& value) : present_(true)
|
||||
{
|
||||
new (&value_) T(ctl::move(value));
|
||||
}
|
||||
|
||||
optional(const optional& other) : present_(other.present_)
|
||||
{
|
||||
if (other.present_)
|
||||
new (&value_) T(other.value_);
|
||||
}
|
||||
|
||||
optional(optional&& other) noexcept : present_(other.present_)
|
||||
{
|
||||
if (other.present_)
|
||||
new (&value_) T(ctl::move(other.value_));
|
||||
}
|
||||
|
||||
optional& operator=(const optional& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
reset();
|
||||
if (other.present_)
|
||||
new (&value_) T(other.value_);
|
||||
present_ = other.present_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional& operator=(optional&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
reset();
|
||||
if (other.present_)
|
||||
new (&value_) T(ctl::move(other.value_));
|
||||
present_ = other.present_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& value() &
|
||||
{
|
||||
if (!present_)
|
||||
__builtin_trap();
|
||||
return value_;
|
||||
}
|
||||
|
||||
const T& value() const&
|
||||
{
|
||||
if (!present_)
|
||||
__builtin_trap();
|
||||
return value_;
|
||||
}
|
||||
|
||||
T&& value() &&
|
||||
{
|
||||
if (!present_)
|
||||
__builtin_trap();
|
||||
return ctl::move(value_);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return present_;
|
||||
}
|
||||
|
||||
bool has_value() const noexcept
|
||||
{
|
||||
return present_;
|
||||
}
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
if (present_) {
|
||||
value_.~T();
|
||||
present_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... args)
|
||||
{
|
||||
reset();
|
||||
present_ = true;
|
||||
new (&value_) T(ctl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void swap(optional& other) noexcept
|
||||
{
|
||||
using ctl::swap;
|
||||
if (present_ && other.present_) {
|
||||
swap(value_, other.value_);
|
||||
} else if (present_) {
|
||||
other.emplace(ctl::move(value_));
|
||||
reset();
|
||||
} else if (other.present_) {
|
||||
emplace(ctl::move(other.value_));
|
||||
other.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
union
|
||||
{
|
||||
T value_;
|
||||
};
|
||||
bool present_;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_
|
||||
@@ -0,0 +1,23 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_OUT_OF_RANGE_H_
|
||||
#define CTL_OUT_OF_RANGE_H_
|
||||
#include "exception.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class out_of_range : public exception
|
||||
{
|
||||
public:
|
||||
out_of_range() noexcept = default;
|
||||
~out_of_range() override = default;
|
||||
|
||||
const char* what() const noexcept override
|
||||
{
|
||||
return "ctl::out_of_range";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_OUT_OF_RANGE_H_
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_PAIR_H_
|
||||
#define CTL_PAIR_H_
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct pair
|
||||
{
|
||||
using first_type = T1;
|
||||
using second_type = T2;
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
|
||||
constexpr pair() : first(), second()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr pair(const T1& x, const T2& y) : first(x), second(y)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr pair(const pair<T1, T2>& p) : first(p.first), second(p.second)
|
||||
{
|
||||
}
|
||||
|
||||
template<class U1, class U2>
|
||||
constexpr pair(U1&& x, U2&& y)
|
||||
: first(ctl::forward<U1>(x)), second(ctl::forward<U2>(y))
|
||||
{
|
||||
}
|
||||
|
||||
template<class U1, class U2>
|
||||
constexpr pair(const pair<U1, U2>& p) : first(p.first), second(p.second)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr pair(pair<T1, T2>&& p)
|
||||
: first(ctl::move(p.first)), second(ctl::move(p.second))
|
||||
{
|
||||
}
|
||||
|
||||
template<class U1, class U2>
|
||||
constexpr pair(pair<U1, U2>&& p)
|
||||
: first(ctl::move(p.first)), second(ctl::move(p.second))
|
||||
{
|
||||
}
|
||||
|
||||
pair& operator=(const pair& other)
|
||||
{
|
||||
first = other.first;
|
||||
second = other.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pair& operator=(pair&& other) noexcept
|
||||
{
|
||||
first = ctl::move(other.first);
|
||||
second = ctl::move(other.second);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U1, class U2>
|
||||
pair& operator=(const pair<U1, U2>& other)
|
||||
{
|
||||
first = other.first;
|
||||
second = other.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U1, class U2>
|
||||
pair& operator=(pair<U1, U2>&& other)
|
||||
{
|
||||
first = ctl::move(other.first);
|
||||
second = ctl::move(other.second);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(pair& other) noexcept
|
||||
{
|
||||
using ctl::swap;
|
||||
swap(first, other.first);
|
||||
swap(second, other.second);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T1, class T2>
|
||||
constexpr pair<T1, T2>
|
||||
make_pair(T1&& t, T2&& u)
|
||||
{
|
||||
return pair<T1, T2>(ctl::forward<T1>(t), ctl::forward<T2>(u));
|
||||
}
|
||||
|
||||
// Comparison operators
|
||||
template<class T1, class T2>
|
||||
constexpr bool
|
||||
operator==(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs)
|
||||
{
|
||||
return lhs.first == rhs.first && lhs.second == rhs.second;
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
constexpr bool
|
||||
operator!=(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
constexpr bool
|
||||
operator<(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs)
|
||||
{
|
||||
return lhs.first < rhs.first ||
|
||||
(!(rhs.first < lhs.first) && lhs.second < rhs.second);
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
constexpr bool
|
||||
operator<=(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
constexpr bool
|
||||
operator>(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
constexpr bool
|
||||
operator>=(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
void
|
||||
swap(pair<T1, T2>& lhs, pair<T1, T2>& rhs) noexcept(noexcept(lhs.swap(rhs)))
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_PAIR_H_
|
||||
@@ -0,0 +1,29 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_PARTITION_H_
|
||||
#define CTL_PARTITION_H_
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename RandomIt, typename Compare>
|
||||
RandomIt
|
||||
partition(RandomIt first, RandomIt last, Compare comp)
|
||||
{
|
||||
auto pivot = *ctl::move(last - 1);
|
||||
auto i = first - 1;
|
||||
|
||||
for (auto j = first; j < last - 1; ++j) {
|
||||
if (comp(*j, pivot)) {
|
||||
++i;
|
||||
ctl::swap(*i, *j);
|
||||
}
|
||||
}
|
||||
|
||||
ctl::swap(*(i + 1), *(last - 1));
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_PARTITION_H_
|
||||
@@ -0,0 +1,49 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_REMOVE_CV_H_
|
||||
#define CTL_REMOVE_CV_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class T>
|
||||
struct remove_const
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct remove_const<const T>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct remove_volatile
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct remove_volatile<volatile T>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct remove_cv
|
||||
{
|
||||
typedef typename remove_volatile<typename remove_const<T>::type>::type type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
using remove_const_t = typename remove_const<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_volatile_t = typename remove_volatile<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_cv_t = typename remove_cv<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_REMOVE_CV_H_
|
||||
@@ -0,0 +1,31 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_REMOVE_EXTENT_H_
|
||||
#define CTL_REMOVE_EXTENT_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct remove_extent
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct remove_extent<T[N]>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_extent<T[]>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using remove_extent_t = typename remove_extent<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_REMOVE_EXTENT_H_
|
||||
@@ -0,0 +1,31 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_REMOVE_REFERENCE_H_
|
||||
#define CTL_REMOVE_REFERENCE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class T>
|
||||
struct remove_reference
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct remove_reference<T&>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct remove_reference<T&&>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
using remove_reference_t = typename remove_reference<T>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_REMOVE_REFERENCE_H_
|
||||
@@ -0,0 +1,183 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_REVERSE_ITERATOR_H_
|
||||
#define CTL_REVERSE_ITERATOR_H_
|
||||
#include "iterator_traits.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class Iterator>
|
||||
class reverse_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_type = Iterator;
|
||||
using iterator_category =
|
||||
typename iterator_traits<Iterator>::iterator_category;
|
||||
using value_type = typename iterator_traits<Iterator>::value_type;
|
||||
using difference_type = typename iterator_traits<Iterator>::difference_type;
|
||||
using pointer = typename iterator_traits<Iterator>::pointer;
|
||||
using reference = typename iterator_traits<Iterator>::reference;
|
||||
|
||||
constexpr reverse_iterator() : current()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr explicit reverse_iterator(Iterator x) : current(x)
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
constexpr reverse_iterator(const reverse_iterator<U>& other)
|
||||
: current(other.base())
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
constexpr reverse_iterator& operator=(const reverse_iterator<U>& other)
|
||||
{
|
||||
current = other.base();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator base() const
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
constexpr reference operator*() const
|
||||
{
|
||||
Iterator tmp = current;
|
||||
return *--tmp;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const
|
||||
{
|
||||
return &(operator*());
|
||||
}
|
||||
|
||||
constexpr reverse_iterator& operator++()
|
||||
{
|
||||
--current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator operator++(int)
|
||||
{
|
||||
reverse_iterator tmp = *this;
|
||||
--current;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator& operator--()
|
||||
{
|
||||
++current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator operator--(int)
|
||||
{
|
||||
reverse_iterator tmp = *this;
|
||||
++current;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator operator+(difference_type n) const
|
||||
{
|
||||
return reverse_iterator(current - n);
|
||||
}
|
||||
|
||||
constexpr reverse_iterator& operator+=(difference_type n)
|
||||
{
|
||||
current -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator operator-(difference_type n) const
|
||||
{
|
||||
return reverse_iterator(current + n);
|
||||
}
|
||||
|
||||
constexpr reverse_iterator& operator-=(difference_type n)
|
||||
{
|
||||
current += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reference operator[](difference_type n) const
|
||||
{
|
||||
return *(*this + n);
|
||||
}
|
||||
|
||||
protected:
|
||||
Iterator current;
|
||||
};
|
||||
|
||||
template<class Iterator1, class Iterator2>
|
||||
constexpr bool
|
||||
operator==(const reverse_iterator<Iterator1>& lhs,
|
||||
const reverse_iterator<Iterator2>& rhs)
|
||||
{
|
||||
return lhs.base() == rhs.base();
|
||||
}
|
||||
|
||||
template<class Iterator1, class Iterator2>
|
||||
constexpr bool
|
||||
operator!=(const reverse_iterator<Iterator1>& lhs,
|
||||
const reverse_iterator<Iterator2>& rhs)
|
||||
{
|
||||
return lhs.base() != rhs.base();
|
||||
}
|
||||
|
||||
template<class Iterator1, class Iterator2>
|
||||
constexpr bool
|
||||
operator<(const reverse_iterator<Iterator1>& lhs,
|
||||
const reverse_iterator<Iterator2>& rhs)
|
||||
{
|
||||
return rhs.base() < lhs.base();
|
||||
}
|
||||
|
||||
template<class Iterator1, class Iterator2>
|
||||
constexpr bool
|
||||
operator<=(const reverse_iterator<Iterator1>& lhs,
|
||||
const reverse_iterator<Iterator2>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<class Iterator1, class Iterator2>
|
||||
constexpr bool
|
||||
operator>(const reverse_iterator<Iterator1>& lhs,
|
||||
const reverse_iterator<Iterator2>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<class Iterator1, class Iterator2>
|
||||
constexpr bool
|
||||
operator>=(const reverse_iterator<Iterator1>& lhs,
|
||||
const reverse_iterator<Iterator2>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<class Iterator>
|
||||
constexpr reverse_iterator<Iterator>
|
||||
operator+(typename reverse_iterator<Iterator>::difference_type n,
|
||||
const reverse_iterator<Iterator>& it)
|
||||
{
|
||||
return reverse_iterator<Iterator>(it.base() - n);
|
||||
}
|
||||
|
||||
template<class Iterator1, class Iterator2>
|
||||
constexpr auto
|
||||
operator-(const reverse_iterator<Iterator1>& lhs,
|
||||
const reverse_iterator<Iterator2>& rhs) -> decltype(rhs.base() -
|
||||
lhs.base())
|
||||
{
|
||||
return rhs.base() - lhs.base();
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_REVERSE_ITERATOR_H_
|
||||
@@ -0,0 +1,33 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_RUNTIME_ERROR_H_
|
||||
#define CTL_RUNTIME_ERROR_H_
|
||||
#include "ctl/string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class runtime_error
|
||||
{
|
||||
public:
|
||||
explicit runtime_error(const string& what_arg) : msg_(what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
explicit runtime_error(const char* what_arg) : msg_(what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~runtime_error() noexcept = default;
|
||||
|
||||
virtual const char* what() const noexcept
|
||||
{
|
||||
return msg_.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
string msg_;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_RUNTIME_ERROR_H_
|
||||
@@ -0,0 +1,945 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_SET_H_
|
||||
#define CTL_SET_H_
|
||||
#include "initializer_list.h"
|
||||
#include "less.h"
|
||||
#include "pair.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Key, typename Compare = less<Key>>
|
||||
class set
|
||||
{
|
||||
struct rbtree
|
||||
{
|
||||
rbtree* left;
|
||||
rbtree* right;
|
||||
rbtree* parent;
|
||||
bool is_red;
|
||||
Key value;
|
||||
|
||||
rbtree(const Key& val)
|
||||
: left(nullptr)
|
||||
, right(nullptr)
|
||||
, parent(nullptr)
|
||||
, is_red(true)
|
||||
, value(val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using value_type = Key;
|
||||
using size_type = size_t;
|
||||
using node_type = rbtree;
|
||||
using key_compare = Compare;
|
||||
using value_compare = Compare;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using const_reference = const value_type&;
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
using value_type = Key;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = Key*;
|
||||
using reference = Key&;
|
||||
|
||||
iterator() : node_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
reference operator*() const
|
||||
{
|
||||
return node_->value;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
return &(node_->value);
|
||||
}
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
if (node_ == nullptr)
|
||||
return *this;
|
||||
if (node_->right) {
|
||||
node_ = leftmost(node_->right);
|
||||
} else {
|
||||
node_type* parent = node_->parent;
|
||||
while (parent && node_ == parent->right) {
|
||||
node_ = parent;
|
||||
parent = parent->parent;
|
||||
}
|
||||
node_ = parent;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator& operator--()
|
||||
{
|
||||
if (node_ == nullptr)
|
||||
__builtin_trap();
|
||||
if (node_->left) {
|
||||
node_ = rightmost(node_->left);
|
||||
} else {
|
||||
node_type* parent = node_->parent;
|
||||
for (;;) {
|
||||
if (parent == nullptr)
|
||||
break;
|
||||
if (node_ == parent->left) {
|
||||
node_ = parent;
|
||||
parent = parent->parent;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
node_ = parent;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator tmp = *this;
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
iterator operator--(int)
|
||||
{
|
||||
iterator tmp = *this;
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& other) const
|
||||
{
|
||||
return node_ == other.node_;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class set;
|
||||
node_type* node_;
|
||||
|
||||
explicit iterator(node_type* node) : node_(node)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class reverse_iterator
|
||||
{
|
||||
public:
|
||||
using value_type = Key;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = Key*;
|
||||
using reference = Key&;
|
||||
|
||||
reverse_iterator() : node_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
reference operator*() const
|
||||
{
|
||||
return node_->value;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
return &(node_->value);
|
||||
}
|
||||
|
||||
reverse_iterator& operator++()
|
||||
{
|
||||
if (node_->left) {
|
||||
node_ = rightmost(node_->left);
|
||||
} else {
|
||||
node_type* parent = node_->parent;
|
||||
while (parent && node_ == parent->left) {
|
||||
node_ = parent;
|
||||
parent = parent->parent;
|
||||
}
|
||||
node_ = parent;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
reverse_iterator operator++(int)
|
||||
{
|
||||
reverse_iterator tmp = *this;
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
reverse_iterator& operator--()
|
||||
{
|
||||
if (node_->right) {
|
||||
node_ = leftmost(node_->right);
|
||||
} else {
|
||||
node_type* parent = node_->parent;
|
||||
while (parent && node_ == parent->right) {
|
||||
node_ = parent;
|
||||
parent = parent->parent;
|
||||
}
|
||||
node_ = parent;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
reverse_iterator operator--(int)
|
||||
{
|
||||
reverse_iterator tmp = *this;
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const reverse_iterator& other) const
|
||||
{
|
||||
return node_ == other.node_;
|
||||
}
|
||||
|
||||
bool operator!=(const reverse_iterator& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
iterator base() const
|
||||
{
|
||||
if (node_ == nullptr)
|
||||
return iterator(leftmost(root_));
|
||||
reverse_iterator tmp = *this;
|
||||
++tmp;
|
||||
return iterator(tmp.node_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class set;
|
||||
node_type* node_;
|
||||
|
||||
explicit reverse_iterator(node_type* node) : node_(node)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using const_iterator = iterator;
|
||||
using const_reverse_iterator = reverse_iterator;
|
||||
|
||||
set() : root_(nullptr), size_(0), comp_(Compare())
|
||||
{
|
||||
}
|
||||
|
||||
explicit set(const Compare& comp) : root_(nullptr), size_(0), comp_(comp)
|
||||
{
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
set(InputIt first, InputIt last, const Compare& comp = Compare())
|
||||
: root_(nullptr), size_(0), comp_(comp)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
insert(*first);
|
||||
}
|
||||
|
||||
set(const set& other) : root_(nullptr), size_(0)
|
||||
{
|
||||
if (other.root_) {
|
||||
root_ = copier(other.root_);
|
||||
size_ = other.size_;
|
||||
}
|
||||
}
|
||||
|
||||
set(set&& other) noexcept : root_(other.root_), size_(other.size_)
|
||||
{
|
||||
other.root_ = nullptr;
|
||||
other.size_ = 0;
|
||||
}
|
||||
|
||||
set(std::initializer_list<value_type> init, const Compare& comp = Compare())
|
||||
: root_(nullptr), size_(0), comp_(comp)
|
||||
{
|
||||
for (const auto& value : init)
|
||||
insert(value);
|
||||
}
|
||||
|
||||
~set()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
set& operator=(const set& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
clear();
|
||||
if (other.root_) {
|
||||
root_ = copier(other.root_);
|
||||
size_ = other.size_;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
set& operator=(set&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
clear();
|
||||
root_ = other.root_;
|
||||
size_ = other.size_;
|
||||
other.root_ = nullptr;
|
||||
other.size_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
size_type size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
iterator begin() noexcept
|
||||
{
|
||||
if (root_)
|
||||
return iterator(leftmost(root_));
|
||||
return iterator(nullptr);
|
||||
}
|
||||
|
||||
const_iterator begin() const noexcept
|
||||
{
|
||||
if (root_)
|
||||
return const_iterator(leftmost(root_));
|
||||
return const_iterator(nullptr);
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
reverse_iterator rbegin()
|
||||
{
|
||||
return reverse_iterator(rightmost(root_));
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const
|
||||
{
|
||||
return const_reverse_iterator(rightmost(root_));
|
||||
}
|
||||
|
||||
const_reverse_iterator crbegin() const
|
||||
{
|
||||
return const_reverse_iterator(rightmost(root_));
|
||||
}
|
||||
|
||||
iterator end() noexcept
|
||||
{
|
||||
return iterator(nullptr);
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept
|
||||
{
|
||||
return const_iterator(nullptr);
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
reverse_iterator rend()
|
||||
{
|
||||
return reverse_iterator(nullptr);
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const
|
||||
{
|
||||
return const_reverse_iterator(nullptr);
|
||||
}
|
||||
|
||||
const_reverse_iterator crend() const
|
||||
{
|
||||
return const_reverse_iterator(nullptr);
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
clearer(root_);
|
||||
root_ = nullptr;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
pair<iterator, bool> insert(value_type&& value)
|
||||
{
|
||||
return insert_node(new node_type(ctl::move(value)));
|
||||
}
|
||||
|
||||
pair<iterator, bool> insert(const value_type& value)
|
||||
{
|
||||
return insert_node(new node_type(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value)
|
||||
{
|
||||
return insert(value).first;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value)
|
||||
{
|
||||
return insert(ctl::move(value)).first;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void insert(InputIt first, InputIt last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
insert(*first);
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
for (const auto& value : ilist)
|
||||
insert(value);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
value_type value(ctl::forward<Args>(args)...);
|
||||
return insert(ctl::move(value));
|
||||
}
|
||||
|
||||
iterator erase(iterator pos)
|
||||
{
|
||||
node_type* node = pos.node_;
|
||||
iterator res = ++pos;
|
||||
erase_node(node);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_type erase(const key_type& key)
|
||||
{
|
||||
node_type* node = get_element(key);
|
||||
if (node == nullptr)
|
||||
return 0;
|
||||
erase_node(node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
while (first != last)
|
||||
first = erase(first);
|
||||
return iterator(const_cast<node_type*>(last.node_));
|
||||
}
|
||||
|
||||
void swap(set& other) noexcept
|
||||
{
|
||||
ctl::swap(root_, other.root_);
|
||||
ctl::swap(size_, other.size_);
|
||||
}
|
||||
|
||||
pair<iterator, iterator> equal_range(const key_type& key)
|
||||
{
|
||||
return { iterator(get_floor(key)), iterator(get_ceiling(key)) };
|
||||
}
|
||||
|
||||
pair<const_iterator, const_iterator> equal_range(const key_type& key) const
|
||||
{
|
||||
return { const_iterator(get_floor(key)),
|
||||
const_iterator(get_ceiling(key)) };
|
||||
}
|
||||
|
||||
iterator lower_bound(const key_type& key)
|
||||
{
|
||||
return iterator(get_floor(key));
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const key_type& key) const
|
||||
{
|
||||
return const_iterator(get_floor(key));
|
||||
}
|
||||
|
||||
iterator upper_bound(const key_type& key)
|
||||
{
|
||||
return iterator(get_ceiling(key));
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const key_type& key) const
|
||||
{
|
||||
return const_iterator(get_ceiling(key));
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const
|
||||
{
|
||||
return !!get_element(key);
|
||||
}
|
||||
|
||||
iterator find(const key_type& key)
|
||||
{
|
||||
return iterator(get_element(key));
|
||||
}
|
||||
|
||||
const_iterator find(const key_type& key) const
|
||||
{
|
||||
return const_iterator(get_element(key));
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
iterator emplace_hint(const_iterator hint, Args&&... args)
|
||||
{
|
||||
return emplace(ctl::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
void check() const
|
||||
{
|
||||
size_type count = 0;
|
||||
if (root_ != nullptr) {
|
||||
if (root_->is_red)
|
||||
// ILLEGAL TREE: root node must be black
|
||||
__builtin_trap();
|
||||
int black_height = -1;
|
||||
checker(root_, nullptr, 0, black_height);
|
||||
count = tally(root_);
|
||||
}
|
||||
if (count != size_)
|
||||
// ILLEGAL TREE: unexpected number of nodes
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
private:
|
||||
static node_type* leftmost(node_type* node) noexcept
|
||||
{
|
||||
while (node && node->left)
|
||||
node = node->left;
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_type* rightmost(node_type* node) noexcept
|
||||
{
|
||||
while (node && node->right)
|
||||
node = node->right;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void clearer(node_type* node) noexcept
|
||||
{
|
||||
node_type* right;
|
||||
for (; node; node = right) {
|
||||
right = node->right;
|
||||
clearer(node->left);
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
static node_type* copier(const node_type* node)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return nullptr;
|
||||
node_type* new_node = new node_type(node->value);
|
||||
new_node->left = copier(node->left);
|
||||
new_node->right = copier(node->right);
|
||||
if (new_node->left)
|
||||
new_node->left->parent = new_node;
|
||||
if (new_node->right)
|
||||
new_node->right->parent = new_node;
|
||||
return new_node;
|
||||
}
|
||||
|
||||
static size_type tally(const node_type* node)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return 0;
|
||||
return 1 + tally(node->left) + tally(node->right);
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
node_type* get_element(const K& key) const
|
||||
{
|
||||
node_type* current = root_;
|
||||
while (current != nullptr) {
|
||||
if (comp_(key, current->value)) {
|
||||
current = current->left;
|
||||
} else if (comp_(current->value, key)) {
|
||||
current = current->right;
|
||||
} else {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
node_type* get_floor(const K& key) const
|
||||
{
|
||||
node_type* result = nullptr;
|
||||
node_type* current = root_;
|
||||
while (current != nullptr) {
|
||||
if (!comp_(current->value, key)) {
|
||||
result = current;
|
||||
current = current->left;
|
||||
} else {
|
||||
current = current->right;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
node_type* get_ceiling(const K& key) const
|
||||
{
|
||||
node_type* result = nullptr;
|
||||
node_type* current = root_;
|
||||
while (current != nullptr) {
|
||||
if (comp_(key, current->value)) {
|
||||
result = current;
|
||||
current = current->left;
|
||||
} else {
|
||||
current = current->right;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pair<iterator, bool> insert_node(node_type* node)
|
||||
{
|
||||
if (root_ == nullptr) {
|
||||
root_ = node;
|
||||
root_->is_red = false;
|
||||
size_++;
|
||||
return { iterator(root_), true };
|
||||
}
|
||||
node_type* current = root_;
|
||||
node_type* parent = nullptr;
|
||||
while (current != nullptr) {
|
||||
parent = current;
|
||||
if (comp_(node->value, current->value)) {
|
||||
current = current->left;
|
||||
} else if (comp_(current->value, node->value)) {
|
||||
current = current->right;
|
||||
} else {
|
||||
delete node; // already exists
|
||||
return { iterator(current), false };
|
||||
}
|
||||
}
|
||||
if (comp_(node->value, parent->value)) {
|
||||
parent->left = node;
|
||||
} else {
|
||||
parent->right = node;
|
||||
}
|
||||
node->parent = parent;
|
||||
size_++;
|
||||
rebalance_after_insert(node);
|
||||
return { iterator(node), true };
|
||||
}
|
||||
|
||||
void erase_node(node_type* node)
|
||||
{
|
||||
node_type* y = node;
|
||||
node_type* x = nullptr;
|
||||
node_type* x_parent = nullptr;
|
||||
bool y_original_color = y->is_red;
|
||||
if (node->left == nullptr) {
|
||||
x = node->right;
|
||||
transplant(node, node->right);
|
||||
x_parent = node->parent;
|
||||
} else if (node->right == nullptr) {
|
||||
x = node->left;
|
||||
transplant(node, node->left);
|
||||
x_parent = node->parent;
|
||||
} else {
|
||||
y = leftmost(node->right);
|
||||
y_original_color = y->is_red;
|
||||
x = y->right;
|
||||
if (y->parent == node) {
|
||||
if (x)
|
||||
x->parent = y;
|
||||
x_parent = y;
|
||||
} else {
|
||||
transplant(y, y->right);
|
||||
y->right = node->right;
|
||||
y->right->parent = y;
|
||||
x_parent = y->parent;
|
||||
}
|
||||
transplant(node, y);
|
||||
y->left = node->left;
|
||||
y->left->parent = y;
|
||||
y->is_red = node->is_red;
|
||||
}
|
||||
if (!y_original_color)
|
||||
rebalance_after_erase(x, x_parent);
|
||||
delete node;
|
||||
--size_;
|
||||
}
|
||||
|
||||
void left_rotate(node_type* x)
|
||||
{
|
||||
node_type* y = x->right;
|
||||
x->right = y->left;
|
||||
if (y->left != nullptr)
|
||||
y->left->parent = x;
|
||||
y->parent = x->parent;
|
||||
if (x->parent == nullptr) {
|
||||
root_ = y;
|
||||
} else if (x == x->parent->left) {
|
||||
x->parent->left = y;
|
||||
} else {
|
||||
x->parent->right = y;
|
||||
}
|
||||
y->left = x;
|
||||
x->parent = y;
|
||||
}
|
||||
|
||||
void right_rotate(node_type* y)
|
||||
{
|
||||
node_type* x = y->left;
|
||||
y->left = x->right;
|
||||
if (x->right != nullptr)
|
||||
x->right->parent = y;
|
||||
x->parent = y->parent;
|
||||
if (y->parent == nullptr) {
|
||||
root_ = x;
|
||||
} else if (y == y->parent->right) {
|
||||
y->parent->right = x;
|
||||
} else {
|
||||
y->parent->left = x;
|
||||
}
|
||||
x->right = y;
|
||||
y->parent = x;
|
||||
}
|
||||
|
||||
void transplant(node_type* u, node_type* v)
|
||||
{
|
||||
if (u->parent == nullptr) {
|
||||
root_ = v;
|
||||
} else if (u == u->parent->left) {
|
||||
u->parent->left = v;
|
||||
} else {
|
||||
u->parent->right = v;
|
||||
}
|
||||
if (v != nullptr)
|
||||
v->parent = u->parent;
|
||||
}
|
||||
|
||||
void checker(const node_type* node,
|
||||
const node_type* parent,
|
||||
int black_count,
|
||||
int& black_height) const
|
||||
{
|
||||
if (node == nullptr) {
|
||||
// Leaf nodes are considered black
|
||||
if (black_height == -1) {
|
||||
black_height = black_count;
|
||||
} else if (black_count != black_height) {
|
||||
// ILLEGAL TREE: Black height mismatch
|
||||
__builtin_trap();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (node->parent != parent)
|
||||
// ILLEGAL TREE: Parent link is incorrect
|
||||
__builtin_trap();
|
||||
if (parent) {
|
||||
if (parent->left == node && !comp_(node->value, parent->value))
|
||||
// ILLEGAL TREE: Binary search property violated on left child
|
||||
__builtin_trap();
|
||||
if (parent->right == node && !comp_(parent->value, node->value))
|
||||
// ILLEGAL TREE: Binary search property violated on right child
|
||||
__builtin_trap();
|
||||
}
|
||||
if (!node->is_red) {
|
||||
black_count++;
|
||||
} else if (parent != nullptr && parent->is_red) {
|
||||
// ILLEGAL TREE: Red node has red child
|
||||
__builtin_trap();
|
||||
}
|
||||
checker(node->left, node, black_count, black_height);
|
||||
checker(node->right, node, black_count, black_height);
|
||||
}
|
||||
|
||||
void rebalance_after_insert(node_type* node)
|
||||
{
|
||||
node->is_red = true;
|
||||
while (node != root_ && node->parent->is_red) {
|
||||
if (node->parent == node->parent->parent->left) {
|
||||
node_type* uncle = node->parent->parent->right;
|
||||
if (uncle && uncle->is_red) {
|
||||
node->parent->is_red = false;
|
||||
uncle->is_red = false;
|
||||
node->parent->parent->is_red = true;
|
||||
node = node->parent->parent;
|
||||
} else {
|
||||
if (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
left_rotate(node);
|
||||
}
|
||||
node->parent->is_red = false;
|
||||
node->parent->parent->is_red = true;
|
||||
right_rotate(node->parent->parent);
|
||||
}
|
||||
} else {
|
||||
node_type* uncle = node->parent->parent->left;
|
||||
if (uncle && uncle->is_red) {
|
||||
node->parent->is_red = false;
|
||||
uncle->is_red = false;
|
||||
node->parent->parent->is_red = true;
|
||||
node = node->parent->parent;
|
||||
} else {
|
||||
if (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
right_rotate(node);
|
||||
}
|
||||
node->parent->is_red = false;
|
||||
node->parent->parent->is_red = true;
|
||||
left_rotate(node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
root_->is_red = false;
|
||||
}
|
||||
|
||||
void rebalance_after_erase(node_type* node, node_type* parent)
|
||||
{
|
||||
while (node != root_ && (node == nullptr || !node->is_red)) {
|
||||
if (node == parent->left) {
|
||||
node_type* sibling = parent->right;
|
||||
if (sibling->is_red) {
|
||||
sibling->is_red = false;
|
||||
parent->is_red = true;
|
||||
left_rotate(parent);
|
||||
sibling = parent->right;
|
||||
}
|
||||
if ((sibling->left == nullptr || !sibling->left->is_red) &&
|
||||
(sibling->right == nullptr || !sibling->right->is_red)) {
|
||||
sibling->is_red = true;
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
} else {
|
||||
if (sibling->right == nullptr || !sibling->right->is_red) {
|
||||
sibling->left->is_red = false;
|
||||
sibling->is_red = true;
|
||||
right_rotate(sibling);
|
||||
sibling = parent->right;
|
||||
}
|
||||
sibling->is_red = parent->is_red;
|
||||
parent->is_red = false;
|
||||
sibling->right->is_red = false;
|
||||
left_rotate(parent);
|
||||
node = root_;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
node_type* sibling = parent->left;
|
||||
if (sibling->is_red) {
|
||||
sibling->is_red = false;
|
||||
parent->is_red = true;
|
||||
right_rotate(parent);
|
||||
sibling = parent->left;
|
||||
}
|
||||
if ((sibling->right == nullptr || !sibling->right->is_red) &&
|
||||
(sibling->left == nullptr || !sibling->left->is_red)) {
|
||||
sibling->is_red = true;
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
} else {
|
||||
if (sibling->left == nullptr || !sibling->left->is_red) {
|
||||
sibling->right->is_red = false;
|
||||
sibling->is_red = true;
|
||||
left_rotate(sibling);
|
||||
sibling = parent->left;
|
||||
}
|
||||
sibling->is_red = parent->is_red;
|
||||
parent->is_red = false;
|
||||
sibling->left->is_red = false;
|
||||
right_rotate(parent);
|
||||
node = root_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node != nullptr)
|
||||
node->is_red = false;
|
||||
}
|
||||
|
||||
node_type* root_;
|
||||
size_type size_;
|
||||
Compare comp_;
|
||||
};
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
bool
|
||||
operator==(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
auto i = lhs.cbegin();
|
||||
auto j = rhs.cbegin();
|
||||
for (; i != lhs.end(); ++i, ++j) {
|
||||
if (!(*i == *j))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
bool
|
||||
operator<(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
auto i = lhs.cbegin();
|
||||
auto j = rhs.cbegin();
|
||||
for (; i != lhs.end() && j != rhs.end(); ++i, ++j) {
|
||||
if (Compare()(*i, *j))
|
||||
return true;
|
||||
if (Compare()(*j, *i))
|
||||
return false;
|
||||
}
|
||||
return i == lhs.end() && j != rhs.end();
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
bool
|
||||
operator!=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
bool
|
||||
operator<=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
bool
|
||||
operator>(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
bool
|
||||
operator>=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
void
|
||||
swap(set<Key, Compare>& lhs, set<Key, Compare>& rhs) noexcept;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_SET_H_
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_SORT_H_
|
||||
#define CTL_SORT_H_
|
||||
#include "iterator_traits.h"
|
||||
#include "less.h"
|
||||
#include "partition.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename RandomIt, typename Compare>
|
||||
void
|
||||
quicksort(RandomIt first, RandomIt last, Compare comp)
|
||||
{
|
||||
if (first < last) {
|
||||
auto pivot = ctl::partition(first, last, comp);
|
||||
quicksort(first, pivot, comp);
|
||||
quicksort(pivot + 1, last, comp);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename RandomIt, typename Compare>
|
||||
void
|
||||
sort(RandomIt first, RandomIt last, Compare comp)
|
||||
{
|
||||
detail::quicksort(first, last, comp);
|
||||
}
|
||||
|
||||
template<typename RandomIt>
|
||||
void
|
||||
sort(RandomIt first, RandomIt last)
|
||||
{
|
||||
sort(first,
|
||||
last,
|
||||
ctl::less<typename ctl::iterator_traits<RandomIt>::value_type>());
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_SORT_H_
|
||||
@@ -0,0 +1,49 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include <stdckdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
string
|
||||
strcat(const string_view lhs, const string_view rhs) noexcept
|
||||
{
|
||||
string res;
|
||||
size_t need;
|
||||
if (ckd_add(&need, lhs.n, rhs.n))
|
||||
__builtin_trap();
|
||||
if (ckd_add(&need, need, 1))
|
||||
__builtin_trap();
|
||||
res.reserve(need);
|
||||
if (lhs.n)
|
||||
memcpy(res.data(), lhs.p, lhs.n);
|
||||
if (rhs.n)
|
||||
memcpy(res.data() + lhs.n, rhs.p, rhs.n);
|
||||
if (res.isbig()) {
|
||||
res.__b.n = lhs.n + rhs.n;
|
||||
} else {
|
||||
res.__s.rem = __::sso_max - lhs.n - rhs.n;
|
||||
}
|
||||
res.data()[res.size()] = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,43 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string_view.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
int
|
||||
strcmp(const string_view lhs, const string_view rhs) noexcept
|
||||
{
|
||||
int r;
|
||||
size_t m = lhs.n;
|
||||
if ((m = rhs.n < m ? rhs.n : m)) {
|
||||
if (!m)
|
||||
return 0;
|
||||
if ((r = memcmp(lhs.p, rhs.p, m)))
|
||||
return r;
|
||||
}
|
||||
if (lhs.n == rhs.n)
|
||||
return 0;
|
||||
if (m < lhs.n)
|
||||
return +1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include <__atomic/fence.h>
|
||||
#include <stdckdint.h>
|
||||
|
||||
namespace ctl {
|
||||
|
||||
void
|
||||
string::destroy_big() noexcept
|
||||
{
|
||||
auto* b = &__b;
|
||||
if (b->n) {
|
||||
if (b->n >= b->c)
|
||||
__builtin_trap();
|
||||
if (b->p[b->n])
|
||||
__builtin_trap();
|
||||
}
|
||||
if (b->c && !b->p)
|
||||
__builtin_trap();
|
||||
free(b->p);
|
||||
}
|
||||
|
||||
void
|
||||
string::init_big(const string& s) noexcept
|
||||
{
|
||||
char* p2;
|
||||
size_t size = s.size();
|
||||
size_t need = size + 1;
|
||||
size_t capacity = need;
|
||||
if (!(p2 = (char*)malloc(capacity)))
|
||||
__builtin_trap();
|
||||
memcpy(p2, s.data(), need);
|
||||
set_big_string(p2, size, capacity);
|
||||
}
|
||||
|
||||
void
|
||||
string::init_big(const string_view s) noexcept
|
||||
{
|
||||
char* p2;
|
||||
size_t need;
|
||||
if (ckd_add(&need, s.n, 1 /* nul */ + 15))
|
||||
__builtin_trap();
|
||||
need &= -16;
|
||||
if (!(p2 = (char*)malloc(need)))
|
||||
__builtin_trap();
|
||||
memcpy(p2, s.p, s.n);
|
||||
p2[s.n] = 0;
|
||||
set_big_string(p2, s.n, need);
|
||||
}
|
||||
|
||||
void
|
||||
string::init_big(const size_t n, const char ch) noexcept
|
||||
{
|
||||
size_t need;
|
||||
char* p2;
|
||||
if (ckd_add(&need, n, 1 /* nul */ + 15))
|
||||
__builtin_trap();
|
||||
need &= -16;
|
||||
if (!(p2 = (char*)malloc(need)))
|
||||
__builtin_trap();
|
||||
memset(p2, ch, n);
|
||||
p2[n] = 0;
|
||||
set_big_string(p2, n, need);
|
||||
}
|
||||
|
||||
const char*
|
||||
string::c_str() const noexcept
|
||||
{
|
||||
if (!size())
|
||||
return "";
|
||||
if (size() >= capacity())
|
||||
__builtin_trap();
|
||||
if (data()[size()])
|
||||
__builtin_trap();
|
||||
return data();
|
||||
}
|
||||
|
||||
void
|
||||
string::reserve(size_t c2) noexcept
|
||||
{
|
||||
char* p2;
|
||||
size_t n = size();
|
||||
if (c2 < n + 1)
|
||||
c2 = n + 1;
|
||||
if (c2 <= __::string_size)
|
||||
return;
|
||||
if (ckd_add(&c2, c2, 15))
|
||||
__builtin_trap();
|
||||
c2 &= -16;
|
||||
if (!isbig()) {
|
||||
if (!(p2 = (char*)malloc(c2)))
|
||||
__builtin_trap();
|
||||
memcpy(p2, data(), __::string_size);
|
||||
} else {
|
||||
if (!(p2 = (char*)realloc(__b.p, c2)))
|
||||
__builtin_trap();
|
||||
}
|
||||
std::atomic_signal_fence(std::memory_order_seq_cst);
|
||||
set_big_string(p2, n, c2);
|
||||
}
|
||||
|
||||
void
|
||||
string::resize(const size_t n2, const char ch) noexcept
|
||||
{
|
||||
size_t c2;
|
||||
if (ckd_add(&c2, n2, 1))
|
||||
__builtin_trap();
|
||||
reserve(c2);
|
||||
if (n2 > size())
|
||||
memset(data() + size(), ch, n2 - size());
|
||||
if (isbig()) {
|
||||
__b.p[__b.n = n2] = 0;
|
||||
} else {
|
||||
set_small_size(n2);
|
||||
data()[size()] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
string::append(const char ch) noexcept
|
||||
{
|
||||
size_t n2;
|
||||
if (ckd_add(&n2, size(), 2))
|
||||
__builtin_trap();
|
||||
if (n2 > capacity()) {
|
||||
size_t c2 = capacity();
|
||||
if (ckd_add(&c2, c2, c2 >> 1))
|
||||
__builtin_trap();
|
||||
reserve(c2);
|
||||
}
|
||||
data()[size()] = ch;
|
||||
if (isbig()) {
|
||||
++__b.n;
|
||||
} else {
|
||||
--__s.rem;
|
||||
}
|
||||
data()[size()] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
string::grow(const size_t size) noexcept
|
||||
{
|
||||
size_t need;
|
||||
if (ckd_add(&need, this->size(), size))
|
||||
__builtin_trap();
|
||||
if (ckd_add(&need, need, 1))
|
||||
__builtin_trap();
|
||||
if (need <= capacity())
|
||||
return;
|
||||
size_t c2 = capacity();
|
||||
if (!c2)
|
||||
__builtin_trap();
|
||||
while (c2 < need)
|
||||
if (ckd_add(&c2, c2, c2 >> 1))
|
||||
__builtin_trap();
|
||||
reserve(c2);
|
||||
}
|
||||
|
||||
void
|
||||
string::append(const char ch, const size_t size) noexcept
|
||||
{
|
||||
grow(size);
|
||||
if (size)
|
||||
memset(data() + this->size(), ch, size);
|
||||
if (isbig()) {
|
||||
__b.n += size;
|
||||
} else {
|
||||
__s.rem -= size;
|
||||
}
|
||||
data()[this->size()] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
string::append(const void* data, const size_t size) noexcept
|
||||
{
|
||||
grow(size);
|
||||
if (size)
|
||||
memcpy(this->data() + this->size(), data, size);
|
||||
if (isbig()) {
|
||||
__b.n += size;
|
||||
} else {
|
||||
__s.rem -= size;
|
||||
}
|
||||
this->data()[this->size()] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
string::pop_back() noexcept
|
||||
{
|
||||
if (!size())
|
||||
__builtin_trap();
|
||||
if (isbig()) {
|
||||
--__b.n;
|
||||
} else {
|
||||
++__s.rem;
|
||||
}
|
||||
data()[size()] = 0;
|
||||
}
|
||||
|
||||
string&
|
||||
string::operator=(string s) noexcept
|
||||
{
|
||||
swap(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
string::operator==(const string_view s) const noexcept
|
||||
{
|
||||
if (size() != s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(data(), s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::operator!=(const string_view s) const noexcept
|
||||
{
|
||||
if (size() != s.n)
|
||||
return true;
|
||||
if (!s.n)
|
||||
return false;
|
||||
return !!memcmp(data(), s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::contains(const string_view s) const noexcept
|
||||
{
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !!memmem(data(), size(), s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::ends_with(const string_view s) const noexcept
|
||||
{
|
||||
if (size() < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(data() + size() - s.n, s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string::starts_with(const string_view s) const noexcept
|
||||
{
|
||||
if (size() < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(data(), s.p, s.n);
|
||||
}
|
||||
|
||||
size_t
|
||||
string::find(const char ch, const size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if ((q = (char*)memchr(data(), ch, size())))
|
||||
return q - data();
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t
|
||||
string::find(const string_view s, const size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if (pos > size())
|
||||
__builtin_trap();
|
||||
if ((q = (char*)memmem(data() + pos, size() - pos, s.p, s.n)))
|
||||
return q - data();
|
||||
return npos;
|
||||
}
|
||||
|
||||
string
|
||||
string::substr(const size_t pos, size_t count) const noexcept
|
||||
{
|
||||
size_t last;
|
||||
if (pos > size())
|
||||
__builtin_trap();
|
||||
if (count > size() - pos)
|
||||
count = size() - pos;
|
||||
if (ckd_add(&last, pos, count))
|
||||
last = size();
|
||||
if (last > size())
|
||||
__builtin_trap();
|
||||
return string(data() + pos, count);
|
||||
}
|
||||
|
||||
string&
|
||||
string::replace(const size_t pos,
|
||||
const size_t count,
|
||||
const string_view s) noexcept
|
||||
{
|
||||
size_t last;
|
||||
if (ckd_add(&last, pos, count))
|
||||
__builtin_trap();
|
||||
if (last > size())
|
||||
__builtin_trap();
|
||||
size_t need;
|
||||
if (ckd_add(&need, pos, s.n))
|
||||
__builtin_trap();
|
||||
size_t extra = size() - last;
|
||||
if (ckd_add(&need, need, extra))
|
||||
__builtin_trap();
|
||||
size_t c2;
|
||||
if (ckd_add(&c2, need, 1))
|
||||
__builtin_trap();
|
||||
reserve(c2);
|
||||
if (extra)
|
||||
memmove(data() + pos + s.n, data() + last, extra);
|
||||
memcpy(data() + pos, s.p, s.n);
|
||||
if (isbig()) {
|
||||
__b.p[__b.n = need] = 0;
|
||||
} else {
|
||||
set_small_size(need);
|
||||
data()[size()] = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::insert(const size_t i, const string_view s) noexcept
|
||||
{
|
||||
if (i > size())
|
||||
__builtin_trap();
|
||||
size_t extra = size() - i;
|
||||
size_t need;
|
||||
if (ckd_add(&need, size(), s.n))
|
||||
__builtin_trap();
|
||||
if (ckd_add(&need, need, 1))
|
||||
__builtin_trap();
|
||||
reserve(need);
|
||||
if (extra)
|
||||
memmove(data() + i + s.n, data() + i, extra);
|
||||
memcpy(data() + i, s.p, s.n);
|
||||
if (isbig()) {
|
||||
__b.n += s.n;
|
||||
} else {
|
||||
__s.rem -= s.n;
|
||||
}
|
||||
data()[size()] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::erase(const size_t pos, size_t count) noexcept
|
||||
{
|
||||
if (pos > size())
|
||||
__builtin_trap();
|
||||
if (count > size() - pos)
|
||||
count = size() - pos;
|
||||
size_t extra = size() - (pos + count);
|
||||
if (extra)
|
||||
memmove(data() + pos, data() + pos + count, extra);
|
||||
if (isbig()) {
|
||||
__b.n = pos + extra;
|
||||
} else {
|
||||
set_small_size(pos + extra);
|
||||
}
|
||||
data()[size()] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
+423
@@ -0,0 +1,423 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_STRING_H_
|
||||
#define CTL_STRING_H_
|
||||
#include "reverse_iterator.h"
|
||||
#include "string_view.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class string;
|
||||
|
||||
string strcat(string_view, string_view) noexcept __wur;
|
||||
|
||||
namespace __ {
|
||||
|
||||
constexpr size_t string_size = 3 * sizeof(size_t);
|
||||
constexpr size_t sso_max = string_size - 1;
|
||||
constexpr size_t big_mask = ~(1ull << (8ull * sizeof(size_t) - 1ull));
|
||||
|
||||
struct small_string
|
||||
{
|
||||
char buf[sso_max];
|
||||
// interpretation is: size == sso_max - rem
|
||||
unsigned char rem;
|
||||
#if 0
|
||||
size_t rem : 7;
|
||||
size_t big : 1 /* = 0 */;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct big_string
|
||||
{
|
||||
char* p;
|
||||
size_t n;
|
||||
// interpretation is: capacity == c & big_mask
|
||||
size_t c;
|
||||
#if 0
|
||||
size_t c : sizeof(size_t) * 8 - 1;
|
||||
size_t big : 1 /* = 1 */;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace __
|
||||
|
||||
class string
|
||||
{
|
||||
public:
|
||||
using value_type = char;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = ctl::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
|
||||
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
string() noexcept
|
||||
{
|
||||
__builtin_memset(blob, 0, sizeof(size_t) * 2);
|
||||
// equivalent to set_small_size(0) but also zeroes memory
|
||||
*(((size_t*)blob) + 2) = __::sso_max << (sizeof(size_t) - 1) * 8;
|
||||
}
|
||||
|
||||
string(const string_view s) noexcept
|
||||
{
|
||||
if (s.n <= __::sso_max) {
|
||||
__builtin_memcpy(blob, s.p, s.n);
|
||||
__builtin_memset(blob + s.n, 0, __::sso_max - s.n);
|
||||
set_small_size(s.n);
|
||||
} else {
|
||||
init_big(s);
|
||||
}
|
||||
}
|
||||
|
||||
explicit string(const size_t n, const char ch = 0) noexcept
|
||||
{
|
||||
if (n <= __::sso_max) {
|
||||
__builtin_memset(blob, ch, n);
|
||||
__builtin_memset(blob + n, 0, __::sso_max - n);
|
||||
set_small_size(n);
|
||||
} else {
|
||||
init_big(n, ch);
|
||||
}
|
||||
}
|
||||
|
||||
string(const char* const p) noexcept
|
||||
: string(string_view(p, __builtin_strlen(p)))
|
||||
{
|
||||
}
|
||||
|
||||
string(const string& r) noexcept
|
||||
{
|
||||
if (r.size() <= __::sso_max) {
|
||||
__builtin_memcpy(blob, r.data(), __::string_size);
|
||||
set_small_size(r.size());
|
||||
} else {
|
||||
init_big(r);
|
||||
}
|
||||
}
|
||||
|
||||
string(const char* const p, const size_t n) noexcept
|
||||
: string(string_view(p, n))
|
||||
{
|
||||
}
|
||||
|
||||
~string() /* noexcept */
|
||||
{
|
||||
if (isbig())
|
||||
destroy_big();
|
||||
}
|
||||
|
||||
string& operator=(string) noexcept;
|
||||
const char* c_str() const noexcept;
|
||||
|
||||
void pop_back() noexcept;
|
||||
void grow(size_t) noexcept;
|
||||
void reserve(size_t) noexcept;
|
||||
void resize(size_t, char = 0) noexcept;
|
||||
void append(char) noexcept;
|
||||
void append(char, size_t) noexcept;
|
||||
void append(unsigned long) noexcept;
|
||||
void append(const void*, size_t) noexcept;
|
||||
string& insert(size_t, string_view) noexcept;
|
||||
string& erase(size_t = 0, size_t = npos) noexcept;
|
||||
string substr(size_t = 0, size_t = npos) const noexcept;
|
||||
string& replace(size_t, size_t, string_view) noexcept;
|
||||
bool operator==(string_view) const noexcept;
|
||||
bool operator!=(string_view) const noexcept;
|
||||
bool contains(string_view) const noexcept;
|
||||
bool ends_with(string_view) const noexcept;
|
||||
bool starts_with(string_view) const noexcept;
|
||||
size_t find(char, size_t = 0) const noexcept;
|
||||
size_t find(string_view, size_t = 0) const noexcept;
|
||||
|
||||
void swap(string& s) noexcept
|
||||
{
|
||||
ctl::swap(blob, s.blob);
|
||||
}
|
||||
|
||||
string(string&& s) noexcept
|
||||
{
|
||||
__builtin_memcpy(blob, s.blob, __::string_size);
|
||||
s.set_small_size(0);
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
if (isbig()) {
|
||||
__b.n = 0;
|
||||
} else {
|
||||
set_small_size(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return isbig() ? !__b.n : __s.rem >= __::sso_max;
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) char* data() noexcept
|
||||
{
|
||||
return isbig() ? __b.p : __s.buf;
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) const char* data() const noexcept
|
||||
{
|
||||
return isbig() ? __b.p : __s.buf;
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) size_t size() const noexcept
|
||||
{
|
||||
#if 0
|
||||
if (!isbig() && __s.rem > __::sso_max)
|
||||
__builtin_trap();
|
||||
#endif
|
||||
return isbig() ? __b.n : __::sso_max - __s.rem;
|
||||
}
|
||||
|
||||
size_t length() const noexcept
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
size_t capacity() const noexcept
|
||||
{
|
||||
#if 0
|
||||
if (isbig() && __b.c <= __::sso_max)
|
||||
__builtin_trap();
|
||||
#endif
|
||||
return isbig() ? __::big_mask & __b.c : __::string_size;
|
||||
}
|
||||
|
||||
iterator begin() noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
const_iterator begin() const noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() noexcept
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator crbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
iterator end() noexcept
|
||||
{
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept
|
||||
{
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept
|
||||
{
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
reverse_iterator rend() noexcept
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
const_reverse_iterator crend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
char& front()
|
||||
{
|
||||
if (!size())
|
||||
__builtin_trap();
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
const char& front() const
|
||||
{
|
||||
if (!size())
|
||||
__builtin_trap();
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
char& back()
|
||||
{
|
||||
if (!size())
|
||||
__builtin_trap();
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
const char& back() const
|
||||
{
|
||||
if (!size())
|
||||
__builtin_trap();
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
char& operator[](size_t i) noexcept
|
||||
{
|
||||
if (i >= size())
|
||||
__builtin_trap();
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
const char& operator[](const size_t i) const noexcept
|
||||
{
|
||||
if (i >= size())
|
||||
__builtin_trap();
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
void push_back(const char ch) noexcept
|
||||
{
|
||||
append(ch);
|
||||
}
|
||||
|
||||
void append(const string_view s) noexcept
|
||||
{
|
||||
append(s.p, s.n);
|
||||
}
|
||||
|
||||
operator string_view() const noexcept
|
||||
{
|
||||
return string_view(data(), size());
|
||||
}
|
||||
|
||||
string& operator=(const char* s) noexcept
|
||||
{
|
||||
clear();
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator=(const string_view s) noexcept
|
||||
{
|
||||
clear();
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator+=(const char x) noexcept
|
||||
{
|
||||
append(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator+=(const string_view s) noexcept
|
||||
{
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string operator+(const string_view s) const noexcept
|
||||
{
|
||||
return strcat(*this, s);
|
||||
}
|
||||
|
||||
int compare(const string_view s) const noexcept
|
||||
{
|
||||
return strcmp(*this, s);
|
||||
}
|
||||
|
||||
bool operator<(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) < 0;
|
||||
}
|
||||
|
||||
bool operator<=(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) <= 0;
|
||||
}
|
||||
|
||||
bool operator>(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) > 0;
|
||||
}
|
||||
|
||||
bool operator>=(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) >= 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void destroy_big() noexcept;
|
||||
void init_big(const string&) noexcept;
|
||||
void init_big(string_view) noexcept;
|
||||
void init_big(size_t, char) noexcept;
|
||||
|
||||
__attribute__((__always_inline__)) bool isbig() const noexcept
|
||||
{
|
||||
return *(blob + __::sso_max) & 0x80;
|
||||
}
|
||||
|
||||
void set_small_size(const size_t size) noexcept
|
||||
{
|
||||
if (size > __::sso_max)
|
||||
__builtin_trap();
|
||||
__s.rem = __::sso_max - size;
|
||||
}
|
||||
|
||||
void set_big_string(char* const p, const size_t n, const size_t c2) noexcept
|
||||
{
|
||||
if (c2 > __::big_mask)
|
||||
__builtin_trap();
|
||||
__b.p = p;
|
||||
__b.n = n;
|
||||
__b.c = c2 | ~__::big_mask;
|
||||
}
|
||||
|
||||
friend string strcat(string_view, string_view) noexcept;
|
||||
|
||||
union
|
||||
{
|
||||
__::big_string __b;
|
||||
__::small_string __s;
|
||||
char blob[__::string_size];
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(string) == __::string_size);
|
||||
static_assert(sizeof(__::small_string) == __::string_size);
|
||||
static_assert(sizeof(__::big_string) == __::string_size);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wliteral-suffix"
|
||||
inline ctl::string
|
||||
operator"" s(const char* s, size_t n)
|
||||
{
|
||||
return ctl::string(s, n);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif // CTL_STRING_H_
|
||||
@@ -0,0 +1,111 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "string_view.h"
|
||||
|
||||
#include <stdckdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
size_t
|
||||
string_view::find(const char ch, const size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if (n && (q = (char*)memchr(p, ch, n)))
|
||||
return q - p;
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t
|
||||
string_view::find(const string_view s, const size_t pos) const noexcept
|
||||
{
|
||||
char* q;
|
||||
if (pos > n)
|
||||
__builtin_trap();
|
||||
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
|
||||
return q - p;
|
||||
return npos;
|
||||
}
|
||||
|
||||
string_view
|
||||
string_view::substr(const size_t pos, size_t count) const noexcept
|
||||
{
|
||||
size_t last;
|
||||
if (pos > n)
|
||||
__builtin_trap();
|
||||
if (count > n - pos)
|
||||
count = n - pos;
|
||||
if (ckd_add(&last, pos, count))
|
||||
last = n;
|
||||
if (last > n)
|
||||
__builtin_trap();
|
||||
return string_view(p + pos, count);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::operator==(const string_view s) const noexcept
|
||||
{
|
||||
if (n != s.n)
|
||||
return false;
|
||||
if (!n)
|
||||
return true;
|
||||
return !memcmp(p, s.p, n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::operator!=(const string_view s) const noexcept
|
||||
{
|
||||
if (n != s.n)
|
||||
return true;
|
||||
if (!n)
|
||||
return false;
|
||||
return !!memcmp(p, s.p, n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::contains(const string_view s) const noexcept
|
||||
{
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !!memmem(p, n, s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::ends_with(const string_view s) const noexcept
|
||||
{
|
||||
if (n < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(p + n - s.n, s.p, s.n);
|
||||
}
|
||||
|
||||
bool
|
||||
string_view::starts_with(const string_view s) const noexcept
|
||||
{
|
||||
if (n < s.n)
|
||||
return false;
|
||||
if (!s.n)
|
||||
return true;
|
||||
return !memcmp(p, s.p, s.n);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,160 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_STRINGVIEW_H_
|
||||
#define COSMOPOLITAN_CTL_STRINGVIEW_H_
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct string_view;
|
||||
|
||||
int
|
||||
strcmp(const string_view, const string_view) noexcept;
|
||||
|
||||
struct string_view
|
||||
{
|
||||
const char* p;
|
||||
size_t n;
|
||||
|
||||
using iterator = const char*;
|
||||
using const_iterator = const char*;
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
constexpr string_view() noexcept : p(nullptr), n(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr string_view(const char* s) noexcept
|
||||
: p(s), n(s ? __builtin_strlen(s) : 0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr string_view(const char* s, const size_t n) noexcept : p(s), n(n)
|
||||
{
|
||||
}
|
||||
|
||||
inline constexpr ~string_view() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(string_view) const noexcept;
|
||||
bool operator!=(string_view) const noexcept;
|
||||
bool contains(string_view) const noexcept;
|
||||
bool ends_with(string_view) const noexcept;
|
||||
bool starts_with(string_view) const noexcept;
|
||||
string_view substr(size_t = 0, size_t = npos) const noexcept;
|
||||
size_t find(char, size_t = 0) const noexcept;
|
||||
size_t find(string_view, size_t = 0) const noexcept;
|
||||
|
||||
constexpr string_view& operator=(const string_view s) noexcept
|
||||
{
|
||||
p = s.p;
|
||||
n = s.n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept
|
||||
{
|
||||
return !n;
|
||||
}
|
||||
|
||||
constexpr const char* data() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
constexpr size_t size() const noexcept
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
constexpr size_t length() const noexcept
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
constexpr const char& operator[](const size_t i) const noexcept
|
||||
{
|
||||
if (i >= n)
|
||||
__builtin_trap();
|
||||
return p[i];
|
||||
}
|
||||
|
||||
constexpr void remove_prefix(const size_t count)
|
||||
{
|
||||
if (count > n)
|
||||
__builtin_trap();
|
||||
p += count;
|
||||
n -= count;
|
||||
}
|
||||
|
||||
constexpr void remove_suffix(const size_t count)
|
||||
{
|
||||
if (count > n)
|
||||
__builtin_trap();
|
||||
n -= count;
|
||||
}
|
||||
|
||||
constexpr const char& front() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[0];
|
||||
}
|
||||
|
||||
constexpr const char& back() const
|
||||
{
|
||||
if (!n)
|
||||
__builtin_trap();
|
||||
return p[n - 1];
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
constexpr const_iterator end() noexcept
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const noexcept
|
||||
{
|
||||
return p + n;
|
||||
}
|
||||
|
||||
int compare(const string_view s) const noexcept
|
||||
{
|
||||
return strcmp(*this, s);
|
||||
}
|
||||
|
||||
bool operator<(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) < 0;
|
||||
}
|
||||
|
||||
bool operator<=(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) <= 0;
|
||||
}
|
||||
|
||||
bool operator>(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) > 0;
|
||||
}
|
||||
|
||||
bool operator>=(const string_view s) const noexcept
|
||||
{
|
||||
return compare(s) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_STRINGVIEW_H_
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_TUPLE_H_
|
||||
#define CTL_TUPLE_H_
|
||||
#include "decay.h"
|
||||
#include "enable_if.h"
|
||||
#include "is_same.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
// Forward declaration
|
||||
template<typename... Types>
|
||||
class tuple;
|
||||
|
||||
// Base case for tuple
|
||||
template<>
|
||||
class tuple<>
|
||||
{};
|
||||
|
||||
// Recursive case for tuple
|
||||
template<typename Head, typename... Tail>
|
||||
class tuple<Head, Tail...> : public tuple<Tail...>
|
||||
{
|
||||
using Base = tuple<Tail...>;
|
||||
|
||||
public:
|
||||
Head head;
|
||||
|
||||
constexpr tuple() : Base(), head()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename H,
|
||||
typename... T,
|
||||
typename = typename ctl::enable_if<
|
||||
!ctl::is_same<typename ctl::decay<H>::type, tuple>::value>::type>
|
||||
constexpr tuple(H&& h, T&&... t)
|
||||
: Base(ctl::forward<T>(t)...), head(ctl::forward<H>(h))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... UTypes>
|
||||
constexpr tuple(const tuple<UTypes...>& other)
|
||||
: Base(static_cast<const tuple<UTypes...>&>(other)), head(other.head)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... UTypes>
|
||||
constexpr tuple(tuple<UTypes...>&& other)
|
||||
: Base(static_cast<tuple<UTypes...>&&>(other))
|
||||
, head(ctl::forward<Head>(other.head))
|
||||
{
|
||||
}
|
||||
|
||||
tuple(const tuple&) = default;
|
||||
tuple(tuple&&) = default;
|
||||
tuple& operator=(const tuple&) = default;
|
||||
tuple& operator=(tuple&&) = default;
|
||||
};
|
||||
|
||||
// Helper struct for getting element type
|
||||
template<size_t I, typename T>
|
||||
struct tuple_element;
|
||||
|
||||
template<size_t I, typename Head, typename... Tail>
|
||||
struct tuple_element<I, tuple<Head, Tail...>>
|
||||
: tuple_element<I - 1, tuple<Tail...>>
|
||||
{};
|
||||
|
||||
template<typename Head, typename... Tail>
|
||||
struct tuple_element<0, tuple<Head, Tail...>>
|
||||
{
|
||||
using type = Head;
|
||||
};
|
||||
|
||||
// Helper function to get element
|
||||
template<size_t I, typename Head, typename... Tail>
|
||||
constexpr typename tuple_element<I, tuple<Head, Tail...>>::type&
|
||||
get(tuple<Head, Tail...>& t)
|
||||
{
|
||||
if constexpr (I == 0) {
|
||||
return t.head;
|
||||
} else {
|
||||
return get<I - 1>(static_cast<tuple<Tail...>&>(t));
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t I, typename Head, typename... Tail>
|
||||
constexpr const typename tuple_element<I, tuple<Head, Tail...>>::type&
|
||||
get(const tuple<Head, Tail...>& t)
|
||||
{
|
||||
if constexpr (I == 0) {
|
||||
return t.head;
|
||||
} else {
|
||||
return get<I - 1>(static_cast<const tuple<Tail...>&>(t));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create a tuple
|
||||
template<typename... Types>
|
||||
constexpr tuple<typename ctl::decay<Types>::type...>
|
||||
make_tuple(Types&&... args)
|
||||
{
|
||||
return tuple<typename ctl::decay<Types>::type...>(
|
||||
ctl::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
// Helper function for tuple comparison
|
||||
template<size_t I = 0, typename... TTypes, typename... UTypes>
|
||||
constexpr bool
|
||||
tuple_equals(const tuple<TTypes...>& t, const tuple<UTypes...>& u)
|
||||
{
|
||||
if constexpr (I == sizeof...(TTypes)) {
|
||||
return true;
|
||||
} else {
|
||||
return get<I>(t) == get<I>(u) && tuple_equals<I + 1>(t, u);
|
||||
}
|
||||
}
|
||||
|
||||
// Equality comparison
|
||||
template<typename... TTypes, typename... UTypes>
|
||||
constexpr bool
|
||||
operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u)
|
||||
{
|
||||
return tuple_equals(t, u);
|
||||
}
|
||||
|
||||
template<typename... TTypes, typename... UTypes>
|
||||
constexpr bool
|
||||
operator!=(const tuple<TTypes...>& t, const tuple<UTypes...>& u)
|
||||
{
|
||||
return !(t == u);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_TUPLE_H_
|
||||
@@ -0,0 +1,29 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_UNINITIALIZED_FILL_H_
|
||||
#define CTL_UNINITIALIZED_FILL_H_
|
||||
#include "addressof.h"
|
||||
#include "iterator_traits.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename ForwardIt, typename T>
|
||||
void
|
||||
uninitialized_fill(ForwardIt first, ForwardIt last, const T& value)
|
||||
{
|
||||
using ValueType = typename ctl::iterator_traits<ForwardIt>::value_type;
|
||||
ForwardIt current = first;
|
||||
try {
|
||||
for (; current != last; ++current)
|
||||
::new (static_cast<void*>(ctl::addressof(*current)))
|
||||
ValueType(value);
|
||||
} catch (...) {
|
||||
for (; first != current; ++first)
|
||||
first->~ValueType();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_UNINITIALIZED_FILL_H_
|
||||
@@ -0,0 +1,52 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_UNINITIALIZED_FILL_N_H_
|
||||
#define CTL_UNINITIALIZED_FILL_N_H_
|
||||
#include "addressof.h"
|
||||
#include "allocator_traits.h"
|
||||
#include "iterator_traits.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename ForwardIt, typename Size, typename T>
|
||||
ForwardIt
|
||||
uninitialized_fill_n(ForwardIt first, Size n, const T& value)
|
||||
{
|
||||
using ValueType = typename ctl::iterator_traits<ForwardIt>::value_type;
|
||||
ForwardIt current = first;
|
||||
try {
|
||||
for (; n > 0; ++current, --n) {
|
||||
::new (static_cast<void*>(ctl::addressof(*current)))
|
||||
ValueType(value);
|
||||
}
|
||||
return current;
|
||||
} catch (...) {
|
||||
for (; first != current; ++first) {
|
||||
first->~ValueType();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ForwardIt, typename Size, typename T, typename Alloc>
|
||||
ForwardIt
|
||||
uninitialized_fill_n(ForwardIt first, Size n, const T& value, Alloc& alloc)
|
||||
{
|
||||
using AllocTraits = ctl::allocator_traits<Alloc>;
|
||||
ForwardIt current = first;
|
||||
try {
|
||||
for (; n > 0; ++current, --n) {
|
||||
AllocTraits::construct(alloc, ctl::addressof(*current), value);
|
||||
}
|
||||
return current;
|
||||
} catch (...) {
|
||||
for (; first != current; ++first) {
|
||||
AllocTraits::destroy(alloc, ctl::addressof(*first));
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_UNINITIALIZED_FILL_N_H_
|
||||
@@ -0,0 +1,52 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_UNINITIALIZED_MOVE_N_H_
|
||||
#define CTL_UNINITIALIZED_MOVE_N_H_
|
||||
#include "addressof.h"
|
||||
#include "allocator_traits.h"
|
||||
#include "iterator_traits.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename InputIt, typename Size, typename ForwardIt>
|
||||
ForwardIt
|
||||
uninitialized_move_n(InputIt first, Size n, ForwardIt d_first)
|
||||
{
|
||||
using T = typename ctl::iterator_traits<ForwardIt>::value_type;
|
||||
ForwardIt current = d_first;
|
||||
try {
|
||||
for (; n > 0; ++first, (void)++current, --n) {
|
||||
::new (static_cast<void*>(ctl::addressof(*current)))
|
||||
T(ctl::move(*first));
|
||||
}
|
||||
} catch (...) {
|
||||
for (; d_first != current; ++d_first) {
|
||||
d_first->~T();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
template<typename InputIt, typename Size, typename ForwardIt, typename Alloc>
|
||||
ForwardIt
|
||||
uninitialized_move_n(InputIt first, Size n, ForwardIt d_first, Alloc& alloc)
|
||||
{
|
||||
using AllocTraits = ctl::allocator_traits<Alloc>;
|
||||
ForwardIt current = d_first;
|
||||
try {
|
||||
for (; n > 0; ++first, (void)++current, --n)
|
||||
AllocTraits::construct(
|
||||
alloc, ctl::addressof(*current), ctl::move(*first));
|
||||
} catch (...) {
|
||||
for (; d_first != current; ++d_first)
|
||||
AllocTraits::destroy(alloc, ctl::addressof(*d_first));
|
||||
throw;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_UNINITIALIZED_MOVE_N_H_
|
||||
@@ -0,0 +1,147 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_UNIQUE_LOCK_H_
|
||||
#define CTL_UNIQUE_LOCK_H_
|
||||
#include "mutex.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct defer_lock_t
|
||||
{
|
||||
explicit defer_lock_t() = default;
|
||||
};
|
||||
|
||||
struct try_to_lock_t
|
||||
{
|
||||
explicit try_to_lock_t() = default;
|
||||
};
|
||||
|
||||
struct adopt_lock_t
|
||||
{
|
||||
explicit adopt_lock_t() = default;
|
||||
};
|
||||
|
||||
inline constexpr defer_lock_t defer_lock{};
|
||||
inline constexpr try_to_lock_t try_to_lock{};
|
||||
inline constexpr adopt_lock_t adopt_lock{};
|
||||
|
||||
class unique_lock
|
||||
{
|
||||
public:
|
||||
unique_lock() noexcept : mutex_(nullptr), owns_lock_(false)
|
||||
{
|
||||
}
|
||||
|
||||
explicit unique_lock(ctl::mutex& m) : mutex_(&m), owns_lock_(false)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
|
||||
unique_lock(ctl::mutex& m, defer_lock_t) noexcept
|
||||
: mutex_(&m), owns_lock_(false)
|
||||
{
|
||||
}
|
||||
|
||||
unique_lock(ctl::mutex& m, try_to_lock_t)
|
||||
: mutex_(&m), owns_lock_(mutex_->try_lock())
|
||||
{
|
||||
}
|
||||
|
||||
unique_lock(ctl::mutex& m, adopt_lock_t) : mutex_(&m), owns_lock_(true)
|
||||
{
|
||||
}
|
||||
|
||||
~unique_lock()
|
||||
{
|
||||
if (owns_lock_)
|
||||
mutex_->unlock();
|
||||
}
|
||||
|
||||
unique_lock(const unique_lock&) = delete;
|
||||
unique_lock& operator=(const unique_lock&) = delete;
|
||||
|
||||
unique_lock(unique_lock&& other) noexcept
|
||||
: mutex_(other.mutex_), owns_lock_(other.owns_lock_)
|
||||
{
|
||||
other.mutex_ = nullptr;
|
||||
other.owns_lock_ = false;
|
||||
}
|
||||
|
||||
unique_lock& operator=(unique_lock&& other) noexcept
|
||||
{
|
||||
if (owns_lock_)
|
||||
mutex_->unlock();
|
||||
mutex_ = other.mutex_;
|
||||
owns_lock_ = other.owns_lock_;
|
||||
other.mutex_ = nullptr;
|
||||
other.owns_lock_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (!mutex_)
|
||||
__builtin_trap();
|
||||
if (owns_lock_)
|
||||
__builtin_trap();
|
||||
mutex_->lock();
|
||||
owns_lock_ = true;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
if (!mutex_)
|
||||
__builtin_trap();
|
||||
if (owns_lock_)
|
||||
__builtin_trap();
|
||||
owns_lock_ = mutex_->try_lock();
|
||||
return owns_lock_;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
if (!owns_lock_)
|
||||
__builtin_trap();
|
||||
mutex_->unlock();
|
||||
owns_lock_ = false;
|
||||
}
|
||||
|
||||
void swap(unique_lock& other) noexcept
|
||||
{
|
||||
using ctl::swap;
|
||||
swap(mutex_, other.mutex_);
|
||||
swap(owns_lock_, other.owns_lock_);
|
||||
}
|
||||
|
||||
ctl::mutex* release() noexcept
|
||||
{
|
||||
ctl::mutex* result = mutex_;
|
||||
mutex_ = nullptr;
|
||||
owns_lock_ = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool owns_lock() const noexcept
|
||||
{
|
||||
return owns_lock_;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return owns_lock_;
|
||||
}
|
||||
|
||||
ctl::mutex* mutex() const noexcept
|
||||
{
|
||||
return mutex_;
|
||||
}
|
||||
|
||||
private:
|
||||
ctl::mutex* mutex_;
|
||||
bool owns_lock_;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_UNIQUE_LOCK_H_
|
||||
@@ -0,0 +1,150 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_UNIQUE_PTR_H_
|
||||
#define CTL_UNIQUE_PTR_H_
|
||||
#include "add_lvalue_reference.h"
|
||||
#include "default_delete.h"
|
||||
#include "is_convertible.h"
|
||||
#include "is_reference.h"
|
||||
#include "is_same.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T, typename D = ctl::default_delete<T>>
|
||||
struct unique_ptr
|
||||
{
|
||||
using pointer = T*;
|
||||
using element_type = T;
|
||||
using deleter_type = D;
|
||||
|
||||
pointer p;
|
||||
[[no_unique_address]] deleter_type d;
|
||||
|
||||
constexpr unique_ptr(const nullptr_t = nullptr) noexcept : p(nullptr), d()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr explicit unique_ptr(pointer p) noexcept : p(p), d()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr unique_ptr(pointer p, const D& d) noexcept : p(p), d(d)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr unique_ptr(pointer p, D&& d) noexcept : p(p), d(ctl::move(d))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename U, typename E>
|
||||
constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept
|
||||
: p(u.release()), d(ctl::forward<E>(u.get_deleter()))
|
||||
{
|
||||
static_assert(ctl::is_convertible<typename unique_ptr<U, E>::pointer,
|
||||
pointer>::value,
|
||||
"U* must be implicitly convertible to T*");
|
||||
static_assert(
|
||||
(ctl::is_reference<D>::value && ctl::is_same<D, E>::value) ||
|
||||
(!ctl::is_reference<D>::value && ctl::is_convertible<E, D>::value),
|
||||
"The deleter must be convertible to the target deleter type");
|
||||
}
|
||||
|
||||
unique_ptr(const unique_ptr&) = delete;
|
||||
|
||||
constexpr ~unique_ptr() noexcept
|
||||
{
|
||||
if (p)
|
||||
d(p);
|
||||
}
|
||||
|
||||
constexpr unique_ptr& operator=(unique_ptr r) noexcept
|
||||
{
|
||||
swap(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U, typename E>
|
||||
constexpr unique_ptr& operator=(unique_ptr<U, E>&& r) noexcept
|
||||
{
|
||||
reset(r.release());
|
||||
d = ctl::forward<E>(r.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr unique_ptr& operator=(nullptr_t) noexcept
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr pointer release() noexcept
|
||||
{
|
||||
pointer r = p;
|
||||
p = nullptr;
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr void reset(pointer p2 = pointer()) noexcept
|
||||
{
|
||||
pointer old = p;
|
||||
p = p2;
|
||||
if (old)
|
||||
d(old);
|
||||
}
|
||||
|
||||
constexpr void swap(unique_ptr& r) noexcept
|
||||
{
|
||||
using ctl::swap;
|
||||
swap(p, r.p);
|
||||
swap(d, r.d);
|
||||
}
|
||||
|
||||
constexpr pointer get() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
constexpr deleter_type& get_deleter() noexcept
|
||||
{
|
||||
return d;
|
||||
}
|
||||
|
||||
constexpr const deleter_type& get_deleter() const noexcept
|
||||
{
|
||||
return d;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept
|
||||
{
|
||||
return p != nullptr;
|
||||
}
|
||||
|
||||
constexpr typename ctl::add_lvalue_reference<T>::type operator*() const
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
constexpr unique_ptr<T>
|
||||
make_unique(Args&&... args)
|
||||
{
|
||||
return unique_ptr<T>(new T(ctl::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr unique_ptr<T>
|
||||
make_unique_for_overwrite()
|
||||
{
|
||||
return unique_ptr<T>(new T);
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_UNIQUE_PTR_H_
|
||||
@@ -0,0 +1,69 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_UTILITY_H_
|
||||
#define COSMOPOLITAN_CTL_UTILITY_H_
|
||||
#include "remove_reference.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
namespace __ {
|
||||
|
||||
template<typename T>
|
||||
struct no_infer_
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using no_infer = typename no_infer_<T>::type;
|
||||
|
||||
} // namespace __
|
||||
|
||||
template<typename T>
|
||||
constexpr T&&
|
||||
move(T&& t) noexcept
|
||||
{
|
||||
typedef remove_reference_t<T> U;
|
||||
return static_cast<U&&>(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T&&
|
||||
move(T& t) noexcept
|
||||
{
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T&&
|
||||
forward(__::no_infer<T>& t) noexcept
|
||||
{
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
// TODO(mrdomino): requires move_constructible<T> && move_assignable<T>
|
||||
constexpr void
|
||||
swap(T& a, T& b) noexcept
|
||||
{
|
||||
T t(ctl::move(a));
|
||||
a = ctl::move(b);
|
||||
b = ctl::move(t);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
// TODO(mrdomino): requires is_swappable
|
||||
constexpr void
|
||||
swap(T (&a)[N], T (&b)[N]) noexcept
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
swap(a[i], b[i]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T&&
|
||||
declval() noexcept;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_UTILITY_H_
|
||||
+594
@@ -0,0 +1,594 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_VECTOR_H_
|
||||
#define CTL_VECTOR_H_
|
||||
#include "allocator.h"
|
||||
#include "allocator_traits.h"
|
||||
#include "copy.h"
|
||||
#include "distance.h"
|
||||
#include "equal.h"
|
||||
#include "fill_n.h"
|
||||
#include "initializer_list.h"
|
||||
#include "iterator_traits.h"
|
||||
#include "lexicographical_compare.h"
|
||||
#include "max.h"
|
||||
#include "move_backward.h"
|
||||
#include "move_iterator.h"
|
||||
#include "out_of_range.h"
|
||||
#include "reverse_iterator.h"
|
||||
#include "uninitialized_fill.h"
|
||||
#include "uninitialized_fill_n.h"
|
||||
#include "uninitialized_move_n.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T, typename Allocator = ctl::allocator<T>>
|
||||
class vector
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using allocator_type = Allocator;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using pointer = typename ctl::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer =
|
||||
typename ctl::allocator_traits<Allocator>::const_pointer;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = ctl::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
|
||||
|
||||
public:
|
||||
vector() noexcept(noexcept(Allocator()))
|
||||
: alloc_(), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit vector(const Allocator& alloc) noexcept
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
}
|
||||
|
||||
vector(size_type count,
|
||||
const T& value,
|
||||
const Allocator& alloc = Allocator())
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
assign(count, value);
|
||||
}
|
||||
|
||||
explicit vector(size_type count, const Allocator& alloc = Allocator())
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
resize(count);
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator())
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
assign(first, last);
|
||||
}
|
||||
|
||||
vector(const vector& other)
|
||||
: alloc_(ctl::allocator_traits<
|
||||
Allocator>::select_on_container_copy_construction(other.alloc_))
|
||||
, data_(nullptr)
|
||||
, size_(0)
|
||||
, capacity_(0)
|
||||
{
|
||||
assign(other.begin(), other.end());
|
||||
}
|
||||
|
||||
vector(const vector& other, const Allocator& alloc)
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
assign(other.begin(), other.end());
|
||||
}
|
||||
|
||||
vector(vector&& other) noexcept
|
||||
: alloc_(ctl::move(other.alloc_))
|
||||
, data_(other.data_)
|
||||
, size_(other.size_)
|
||||
, capacity_(other.capacity_)
|
||||
{
|
||||
other.data_ = nullptr;
|
||||
other.size_ = 0;
|
||||
other.capacity_ = 0;
|
||||
}
|
||||
|
||||
vector(vector&& other, const Allocator& alloc)
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
if (alloc_ == other.alloc_) {
|
||||
data_ = other.data_;
|
||||
size_ = other.size_;
|
||||
capacity_ = other.capacity_;
|
||||
other.data_ = nullptr;
|
||||
other.size_ = 0;
|
||||
other.capacity_ = 0;
|
||||
} else {
|
||||
assign(ctl::make_move_iterator(other.begin()),
|
||||
ctl::make_move_iterator(other.end()));
|
||||
}
|
||||
}
|
||||
|
||||
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator())
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
assign(init.begin(), init.end());
|
||||
}
|
||||
|
||||
~vector()
|
||||
{
|
||||
clear();
|
||||
ctl::allocator_traits<Allocator>::deallocate(alloc_, data_, capacity_);
|
||||
}
|
||||
|
||||
vector& operator=(const vector& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
if (ctl::allocator_traits<
|
||||
Allocator>::propagate_on_container_copy_assignment::value)
|
||||
alloc_ = other.alloc_;
|
||||
assign(other.begin(), other.end());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector& operator=(vector&& other) noexcept(
|
||||
ctl::allocator_traits<Allocator>::is_always_equal::value)
|
||||
{
|
||||
if (this != &other) {
|
||||
clear();
|
||||
ctl::allocator_traits<Allocator>::deallocate(
|
||||
alloc_, data_, capacity_);
|
||||
if (ctl::allocator_traits<
|
||||
Allocator>::propagate_on_container_move_assignment::value)
|
||||
alloc_ = ctl::move(other.alloc_);
|
||||
data_ = other.data_;
|
||||
size_ = other.size_;
|
||||
capacity_ = other.capacity_;
|
||||
other.data_ = nullptr;
|
||||
other.size_ = 0;
|
||||
other.capacity_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector& operator=(std::initializer_list<T> ilist)
|
||||
{
|
||||
assign(ilist.begin(), ilist.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void assign(size_type count, const T& value)
|
||||
{
|
||||
clear();
|
||||
if (count > capacity_)
|
||||
reallocate(count);
|
||||
ctl::uninitialized_fill_n(data_, count, value);
|
||||
size_ = count;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void assign(InputIt first, InputIt last)
|
||||
{
|
||||
clear();
|
||||
for (; first != last; ++first)
|
||||
push_back(*first);
|
||||
}
|
||||
|
||||
void assign(std::initializer_list<T> ilist)
|
||||
{
|
||||
assign(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
reference at(size_type pos)
|
||||
{
|
||||
if (pos >= size_)
|
||||
throw ctl::out_of_range("out of range");
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= size_)
|
||||
throw ctl::out_of_range("out of range");
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
reference operator[](size_type pos)
|
||||
{
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
const_reference operator[](size_type pos) const
|
||||
{
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
reference front()
|
||||
{
|
||||
return data_[0];
|
||||
}
|
||||
|
||||
const_reference front() const
|
||||
{
|
||||
return data_[0];
|
||||
}
|
||||
|
||||
reference back()
|
||||
{
|
||||
return data_[size_ - 1];
|
||||
}
|
||||
|
||||
const_reference back() const
|
||||
{
|
||||
return data_[size_ - 1];
|
||||
}
|
||||
|
||||
T* data() noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const T* data() const noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
iterator begin() noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const_iterator begin() const noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
iterator end() noexcept
|
||||
{
|
||||
return data_ + size_;
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept
|
||||
{
|
||||
return data_ + size_;
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept
|
||||
{
|
||||
return data_ + size_;
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() noexcept
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator crbegin() 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_reverse_iterator crend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
size_type size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
size_type max_size() const noexcept
|
||||
{
|
||||
return __PTRDIFF_MAX__;
|
||||
}
|
||||
|
||||
size_type capacity() const noexcept
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
void reserve(size_type new_cap)
|
||||
{
|
||||
if (new_cap > capacity_)
|
||||
reallocate(new_cap);
|
||||
}
|
||||
|
||||
void shrink_to_fit()
|
||||
{
|
||||
if (size_ < capacity_)
|
||||
reallocate(size_);
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
for (size_type i = 0; i < size_; ++i)
|
||||
ctl::allocator_traits<Allocator>::destroy(alloc_, data_ + i);
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator pos, const T& value)
|
||||
{
|
||||
return insert(pos, 1, value);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator pos, T&& value)
|
||||
{
|
||||
difference_type index = pos - begin();
|
||||
if (size_ == capacity_)
|
||||
grow();
|
||||
iterator it = begin() + index;
|
||||
ctl::move_backward(it, end(), end() + 1);
|
||||
*it = ctl::move(value);
|
||||
++size_;
|
||||
return it;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator pos, size_type count, const T& value)
|
||||
{
|
||||
difference_type index = pos - begin();
|
||||
if (size_ + count > capacity_)
|
||||
reallocate(ctl::max(size_ + count, capacity_ * 2));
|
||||
iterator it = begin() + index;
|
||||
ctl::move_backward(it, end(), end() + count);
|
||||
ctl::fill_n(it, count, value);
|
||||
size_ += count;
|
||||
return it;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
iterator insert(const_iterator pos, InputIt first, InputIt last)
|
||||
{
|
||||
difference_type count = ctl::distance(first, last);
|
||||
difference_type index = pos - begin();
|
||||
if (size_ + count > capacity_)
|
||||
reallocate(ctl::max(size_ + count, capacity_ * 2));
|
||||
iterator it = begin() + index;
|
||||
ctl::move_backward(it, end(), end() + count);
|
||||
ctl::copy(first, last, it);
|
||||
size_ += count;
|
||||
return it;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator pos, std::initializer_list<T> ilist)
|
||||
{
|
||||
return insert(pos, ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
iterator emplace(const_iterator pos, Args&&... args)
|
||||
{
|
||||
difference_type index = pos - begin();
|
||||
if (size_ == capacity_)
|
||||
grow();
|
||||
iterator it = begin() + index;
|
||||
ctl::move_backward(it, end(), end() + 1);
|
||||
ctl::allocator_traits<Allocator>::construct(
|
||||
alloc_, it, ctl::forward<Args>(args)...);
|
||||
++size_;
|
||||
return it;
|
||||
}
|
||||
|
||||
iterator erase(const_iterator pos)
|
||||
{
|
||||
return erase(pos, pos + 1);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
difference_type index = first - begin();
|
||||
difference_type count = last - first;
|
||||
iterator it = begin() + index;
|
||||
ctl::move(it + count, end(), it);
|
||||
for (difference_type i = 0; i < count; ++i)
|
||||
ctl::allocator_traits<Allocator>::destroy(alloc_, end() - i - 1);
|
||||
size_ -= count;
|
||||
return it;
|
||||
}
|
||||
|
||||
void push_back(const T& value)
|
||||
{
|
||||
if (size_ == capacity_)
|
||||
grow();
|
||||
ctl::allocator_traits<Allocator>::construct(
|
||||
alloc_, data_ + size_, value);
|
||||
++size_;
|
||||
}
|
||||
|
||||
void push_back(T&& value)
|
||||
{
|
||||
if (size_ == capacity_)
|
||||
grow();
|
||||
ctl::allocator_traits<Allocator>::construct(
|
||||
alloc_, data_ + size_, ctl::move(value));
|
||||
++size_;
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
reference emplace_back(Args&&... args)
|
||||
{
|
||||
if (size_ == capacity_)
|
||||
grow();
|
||||
ctl::allocator_traits<Allocator>::construct(
|
||||
alloc_, data_ + size_, ctl::forward<Args>(args)...);
|
||||
return data_[size_++];
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
if (!empty()) {
|
||||
ctl::allocator_traits<Allocator>::destroy(alloc_,
|
||||
data_ + size_ - 1);
|
||||
--size_;
|
||||
}
|
||||
}
|
||||
|
||||
void resize(size_type count)
|
||||
{
|
||||
resize(count, T());
|
||||
}
|
||||
|
||||
void resize(size_type count, const value_type& value)
|
||||
{
|
||||
if (count > size_) {
|
||||
if (count > capacity_)
|
||||
reallocate(count);
|
||||
ctl::uninitialized_fill(data_ + size_, data_ + count, value);
|
||||
} else if (count < size_) {
|
||||
for (size_type i = count; i < size_; ++i)
|
||||
ctl::allocator_traits<Allocator>::destroy(alloc_, data_ + i);
|
||||
}
|
||||
size_ = count;
|
||||
}
|
||||
|
||||
void swap(vector& other) noexcept(
|
||||
ctl::allocator_traits<Allocator>::is_always_equal::value)
|
||||
{
|
||||
using ctl::swap;
|
||||
swap(alloc_, other.alloc_);
|
||||
swap(data_, other.data_);
|
||||
swap(size_, other.size_);
|
||||
swap(capacity_, other.capacity_);
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const noexcept
|
||||
{
|
||||
return alloc_;
|
||||
}
|
||||
|
||||
private:
|
||||
void grow()
|
||||
{
|
||||
size_type c2;
|
||||
c2 = capacity_;
|
||||
if (c2 < 4)
|
||||
c2 = 4;
|
||||
c2 += c2 >> 1;
|
||||
reallocate(c2);
|
||||
}
|
||||
|
||||
void reallocate(size_type new_capacity)
|
||||
{
|
||||
pointer new_data =
|
||||
ctl::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
|
||||
size_type new_size = size_ < new_capacity ? size_ : new_capacity;
|
||||
try {
|
||||
ctl::uninitialized_move_n(data_, new_size, new_data);
|
||||
} catch (...) {
|
||||
ctl::allocator_traits<Allocator>::deallocate(
|
||||
alloc_, new_data, new_capacity);
|
||||
throw;
|
||||
}
|
||||
for (size_type i = 0; i < size_; ++i)
|
||||
ctl::allocator_traits<Allocator>::destroy(alloc_, data_ + i);
|
||||
ctl::allocator_traits<Allocator>::deallocate(alloc_, data_, capacity_);
|
||||
data_ = new_data;
|
||||
size_ = new_size;
|
||||
capacity_ = new_capacity;
|
||||
}
|
||||
|
||||
Allocator alloc_;
|
||||
pointer data_;
|
||||
size_type size_;
|
||||
size_type capacity_;
|
||||
};
|
||||
|
||||
template<class T, class Alloc>
|
||||
bool
|
||||
operator==(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
|
||||
{
|
||||
return lhs.size() == rhs.size() &&
|
||||
ctl::equal(lhs.begin(), lhs.end(), rhs.begin());
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
bool
|
||||
operator!=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
bool
|
||||
operator<(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
|
||||
{
|
||||
return ctl::lexicographical_compare(
|
||||
lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
bool
|
||||
operator<=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
bool
|
||||
operator>(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
bool
|
||||
operator>=(const vector<T, Alloc>& lhs, const vector<T, Alloc>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
void
|
||||
swap(vector<T, Alloc>& lhs,
|
||||
vector<T, Alloc>& rhs) noexcept(noexcept(lhs.swap(rhs)))
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<class InputIt,
|
||||
class Alloc =
|
||||
ctl::allocator<typename ctl::iterator_traits<InputIt>::value_type>>
|
||||
vector(InputIt, InputIt, Alloc = Alloc())
|
||||
-> vector<typename ctl::iterator_traits<InputIt>::value_type, Alloc>;
|
||||
|
||||
template<class Alloc>
|
||||
vector(size_t,
|
||||
const typename ctl::allocator_traits<Alloc>::value_type&,
|
||||
Alloc = Alloc())
|
||||
-> vector<typename ctl::allocator_traits<Alloc>::value_type, Alloc>;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_VECTOR_H_
|
||||
@@ -0,0 +1,13 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_VOID_T_H_
|
||||
#define CTL_VOID_T_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename... Ts>
|
||||
using void_t = void;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_VOID_T_H_
|
||||
Loaded 100 of 2944 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user