mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-12 16:09:42 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e08a4cd99e | ||
|
|
7ebaff34c6 | ||
|
|
e7be5a5e2b | ||
|
|
30afd6ddbb | ||
|
|
d3167126aa | ||
|
|
d3f87f4c64 | ||
|
|
29ce25c767 | ||
|
|
7996bf67b5 | ||
|
|
626a5d02ee | ||
|
|
527aaa41eb | ||
|
|
421a819d88 | ||
|
|
3374cbba73 | ||
|
|
2018cac11f | ||
|
|
6a5d4ed65b | ||
|
|
493ffc9b7f | ||
|
|
101fb3d9b3 | ||
|
|
f6ba270ff3 | ||
|
|
86d884cce2 | ||
|
|
0ed916ad5c | ||
|
|
1029dcc597 | ||
|
|
c697133a2d | ||
|
|
1ff037df3c | ||
|
|
567d8fe32d | ||
|
|
23dfb79d33 | ||
|
|
76cea6c687 | ||
|
|
63065cdd70 | ||
|
|
3f2a1b696e | ||
|
|
f590e96abd | ||
|
|
f7780de24b | ||
|
|
196942084b | ||
|
|
6be030cd7c | ||
|
|
8c645fa1ee | ||
|
|
3756870635 | ||
|
|
fc65422660 | ||
|
|
01587de761 | ||
|
|
5a9a08d1cf | ||
|
|
bd6d9ff99a | ||
|
|
15ea0524b3 | ||
|
|
fdab49b30e | ||
|
|
135d538b1d | ||
|
|
6dbc3fba18 | ||
|
|
70f77aad33 | ||
|
|
d0cd719375 | ||
|
|
61370983e1 | ||
|
|
72511ff0ac | ||
|
|
c1f8d0678c | ||
|
|
e627bfa359 | ||
|
|
acbabedf27 | ||
|
|
239f8ce76e | ||
|
|
ca4cf67eb8 | ||
|
|
78d3b86ec7 | ||
|
|
44191b3f50 | ||
|
|
e437bed006 | ||
|
|
76957983cf | ||
|
|
387310c659 | ||
|
|
4cb5e21ba8 | ||
|
|
1bf2d8e308 | ||
|
|
98e684622b |
No files matched your search
@@ -25,3 +25,5 @@ c0eacf2eb1e1c0b3bd4f71f12fef258f5b249c3f
|
||||
da8baf2aa5ce93b958aca90a0ae69f537806324b
|
||||
# Run clang-format on most sources
|
||||
369f9740de4534c28d0e81ab2afc99decbb9a3e6
|
||||
# Get rid of .internal.h convention in LIBC_INTRIN
|
||||
86d884cce24d773e298a2714c1e3d91ecab9be45
|
||||
@@ -101,19 +101,20 @@ XARGS ?= xargs -P4 -rs8000
|
||||
DOT ?= dot
|
||||
CLANG = clang
|
||||
TMPDIR = o/tmp
|
||||
AR = build/bootstrap/ar
|
||||
CP = build/bootstrap/cp
|
||||
RM = build/bootstrap/rm -f
|
||||
GZIP = build/bootstrap/gzip
|
||||
ECHO = build/bootstrap/echo
|
||||
CHMOD = build/bootstrap/chmod
|
||||
TOUCH = build/bootstrap/touch
|
||||
PKG = build/bootstrap/package
|
||||
MKDEPS = build/bootstrap/mkdeps
|
||||
ZIPOBJ = build/bootstrap/zipobj
|
||||
ZIPCOPY = build/bootstrap/zipcopy
|
||||
PECHECK = build/bootstrap/pecheck
|
||||
FIXUPOBJ = build/bootstrap/fixupobj
|
||||
AR = $(BOOTSTRAP)/ar.ape
|
||||
CP = $(BOOTSTRAP)/cp.ape
|
||||
RM = $(BOOTSTRAP)/rm.ape -f
|
||||
GZIP = $(BOOTSTRAP)/gzip.ape
|
||||
ECHO = $(BOOTSTRAP)/echo.ape
|
||||
CHMOD = $(BOOTSTRAP)/chmod.ape
|
||||
TOUCH = $(BOOTSTRAP)/touch.ape
|
||||
PKG = $(BOOTSTRAP)/package.ape
|
||||
MKDEPS = $(BOOTSTRAP)/mkdeps
|
||||
ZIPOBJ = $(BOOTSTRAP)/zipobj
|
||||
ZIPCOPY = $(BOOTSTRAP)/zipcopy
|
||||
PECHECK = $(BOOTSTRAP)/pecheck
|
||||
FIXUPOBJ = $(BOOTSTRAP)/fixupobj
|
||||
OBJBINCOPY = $(BOOTSTRAP)/objbincopy
|
||||
MKDIR = build/bootstrap/mkdir -p
|
||||
COMPILE = build/bootstrap/compile -V9 -M2048m -P8192 $(QUOTA)
|
||||
|
||||
@@ -149,9 +150,10 @@ export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
COSMOCC = .cosmocc/3.3.5
|
||||
COSMOCC = .cosmocc/3.5.7
|
||||
BOOTSTRAP = $(COSMOCC)/bin
|
||||
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.3.5 db78fd8d3f8706e9dff4be72bf71d37a3f12062f212f407e1c33bc4af3780dd0)
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.5.7 596876951b62ad2530c63afc40edd805d751fcb2416e544d249af04ad00bb4ed)
|
||||
|
||||
AS = $(TOOLCHAIN)as
|
||||
CC = $(TOOLCHAIN)gcc
|
||||
@@ -256,7 +258,6 @@ 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 # │
|
||||
@@ -285,9 +286,10 @@ include third_party/ncurses/BUILD.mk # │
|
||||
include third_party/readline/BUILD.mk # │
|
||||
include third_party/libunwind/BUILD.mk # |
|
||||
include third_party/libcxxabi/BUILD.mk # |
|
||||
include third_party/double-conversion/BUILD.mk # │
|
||||
include ctl/BUILD.mk # │
|
||||
include third_party/libcxx/BUILD.mk # │
|
||||
include third_party/openmp/BUILD.mk # │
|
||||
include third_party/double-conversion/BUILD.mk # │
|
||||
include third_party/pcre/BUILD.mk # │
|
||||
include third_party/less/BUILD.mk # │
|
||||
include net/https/BUILD.mk # │
|
||||
@@ -434,6 +436,9 @@ loc: o/$(MODE)/tool/build/summy
|
||||
# PLEASE: MAINTAIN TOPOLOGICAL ORDER
|
||||
# FROM HIGHEST LEVEL TO LOWEST LEVEL
|
||||
COSMOPOLITAN_OBJECTS = \
|
||||
CTL \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_OPENMP \
|
||||
TOOL_ARGS \
|
||||
NET_HTTP \
|
||||
LIBC_SOCK \
|
||||
@@ -443,7 +448,6 @@ COSMOPOLITAN_OBJECTS = \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
THIRD_PARTY_TZ \
|
||||
THIRD_PARTY_OPENMP \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
@@ -454,7 +458,6 @@ COSMOPOLITAN_OBJECTS = \
|
||||
LIBC_THREAD \
|
||||
LIBC_PROC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
CTL \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_DLOPEN \
|
||||
|
||||
+2
-2
@@ -218,10 +218,10 @@ o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=8 -S -g0 $(APE_LOADER_FLAGS)
|
||||
|
||||
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy -f -o $@ $<
|
||||
@$(COMPILE) -AOBJBINCOPY -w $(OBJBINCOPY) -f -o $@ $<
|
||||
|
||||
o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.elf.dbg
|
||||
@$(COMPILE) -AOBJBINCOPY -w build/bootstrap/objbincopy -fm -o $@ $<
|
||||
@$(COMPILE) -AOBJBINCOPY -w $(OBJBINCOPY) -fm -o $@ $<
|
||||
|
||||
APE_LOADER_LDFLAGS = \
|
||||
-static \
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ OUTPUT_FORMAT("elf64-littleaarch64",
|
||||
|
||||
SECTIONS {
|
||||
|
||||
. = SEGMENT_START("text-segment", 0x010000000000);
|
||||
. = SEGMENT_START("text-segment", 0x000800000000);
|
||||
__executable_start = .;
|
||||
. += SIZEOF_HEADERS;
|
||||
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
# Actually Portable Executable Specification v0.1
|
||||
|
||||
Actually Portable Executable (APE) is an executable file format that
|
||||
polyglots the Windows Portable Executable (PE) format with a UNIX Sixth
|
||||
Edition style shell script that doesn't have a shebang. This makes it
|
||||
possible to produce a single file binary that executes on the stock
|
||||
installations of the many OSes and architectures.
|
||||
|
||||
## Supported OSes and Architectures
|
||||
|
||||
- AMD64
|
||||
- Linux
|
||||
- MacOS
|
||||
- Windows
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- BIOS
|
||||
|
||||
- ARM64
|
||||
- Linux
|
||||
- MacOS
|
||||
- FreeBSD
|
||||
- Windows (non-native)
|
||||
|
||||
## File Header
|
||||
|
||||
APE defines three separate file magics, all of which are 8 characters
|
||||
long. Any file that starts with one of these magic values can be
|
||||
considered an APE program.
|
||||
|
||||
### (1) APE MZ Magic
|
||||
|
||||
- ASCII: `MZqFpD='`
|
||||
- Hex: 4d 5a 71 46 70 44 3d 27
|
||||
|
||||
This is the canonical magic used by almost all APE programs. It enables
|
||||
maximum portability between OSes. When interpreted as a shell script, it
|
||||
is assiging a single quoted string to an unused variable. The shell will
|
||||
then ignore subsequent binary content that's placed inside the string.
|
||||
|
||||
It is strongly recommended that this magic value be immediately followed
|
||||
by a newline (\n or hex 0a) character. Some shells, e.g. FreeBSD SH and
|
||||
Zsh impose a binary safety check before handing off files that don't
|
||||
have a shebang to `/bin/sh`. That check applies to the first line, which
|
||||
can't contain NUL characters.
|
||||
|
||||
The letters were carefully chosen so as to be valid x86 instructions in
|
||||
all operating modes. This makes it possible to store a BIOS bootloader
|
||||
disk image inside an APE binary. For example, simple CLI programs built
|
||||
with Cosmopolitan Libc will boot from BIOS into long mode if they're
|
||||
treated as a floppy disk image.
|
||||
|
||||
The letters also allow for the possibility of being treated on x86-64 as
|
||||
a flat executable, where the PE / ELF / Mach-O executable structures are
|
||||
ignored, and execution simply begins at the beginning of the file,
|
||||
similar to how MS-DOS .COM binaries work.
|
||||
|
||||
The 0x4a relative offset of the magic causes execution to jump into the
|
||||
MS-DOS stub defined by Portable Executable. APE binaries built by Cosmo
|
||||
Libc use tricks in the MS-DOS stub to check the operating mode and then
|
||||
jump to the appropriate entrypoint, e.g. `_start()`.
|
||||
|
||||
#### Decoded as i8086
|
||||
|
||||
```asm
|
||||
dec %bp
|
||||
pop %dx
|
||||
jno 0x4a
|
||||
jo 0x4a
|
||||
```
|
||||
|
||||
#### Decoded as i386
|
||||
|
||||
```asm
|
||||
push %ebp
|
||||
pop %edx
|
||||
jno 0x4a
|
||||
jo 0x4a
|
||||
```
|
||||
|
||||
#### Decoded as x86-64
|
||||
|
||||
```asm
|
||||
rex.WRB
|
||||
pop %r10
|
||||
jno 0x4a
|
||||
jo 0x4a
|
||||
```
|
||||
|
||||
### (2) APE UNIX-Only Magic
|
||||
|
||||
- ASCII: `jartsr='`
|
||||
- Hex: 6a 61 72 74 73 72 3d 27
|
||||
|
||||
Being a novel executable format that was first published in 2020, the
|
||||
APE file format is less understood by industry tools compared to the PE,
|
||||
ELF, and Mach-O executable file formats, which have been around for
|
||||
decades. For this reason, APE programs that use the MZ magic above can
|
||||
attract attention from Windows AV software, which may be unwanted by
|
||||
developers who aren't interested in targeting the Windows platform.
|
||||
Therefore the `jartsr='` magic is defined which enables the creation of
|
||||
APE binaries that can safely target all non-Windows platforms. Even
|
||||
though this magic is less common, APE interpreters and binfmt-misc
|
||||
installations MUST support this.
|
||||
|
||||
It is strongly recommended that this magic value be immediately followed
|
||||
by a newline (\n or hex 0a) character. Some shells, e.g. FreeBSD SH and
|
||||
Zsh impose a binary safety check before handing off files that don't
|
||||
have a shebang to `/bin/sh`. That check applies to the first line, which
|
||||
can't contain NUL characters.
|
||||
|
||||
The letters were carefully chosen so as to be valid x86 instructions in
|
||||
all operating modes. This makes it possible to store a BIOS bootloader
|
||||
disk image inside an APE binary. For example, simple CLI programs built
|
||||
with Cosmopolitan Libc will boot from BIOS into long mode if they're
|
||||
treated as a floppy disk image.
|
||||
|
||||
The letters also allow for the possibility of being treated on x86-64 as
|
||||
a flat executable, where the PE / ELF / Mach-O executable structures are
|
||||
ignored, and execution simply begins at the beginning of the file,
|
||||
similar to how MS-DOS .COM binaries work.
|
||||
|
||||
The 0x78 relative offset of the magic causes execution to jump into the
|
||||
MS-DOS stub defined by Portable Executable. APE binaries built by Cosmo
|
||||
Libc use tricks in the MS-DOS stub to check the operating mode and then
|
||||
jump to the appropriate entrypoint, e.g. `_start()`.
|
||||
|
||||
#### Decoded as i8086 / i386 / x86-64
|
||||
|
||||
```asm
|
||||
push $0x61
|
||||
jb 0x78
|
||||
jae 0x78
|
||||
```
|
||||
|
||||
### (3) APE Debug Magic
|
||||
|
||||
- ASCII: `APEDBG='`
|
||||
- Hex: 41 50 45 44 42 47 3d 27
|
||||
|
||||
While APE files must be valid shell scripts, in practice, UNIX systems
|
||||
will oftentimes be configured to provide a faster safer alternative to
|
||||
loading an APE binary through `/bin/sh`. The Linux Kernel can be patched
|
||||
to have execve() recognize the APE format and directly load its embedded
|
||||
ELF header. Linux systems can also use binfmt-misc to recognize APE's MZ
|
||||
and jartsr magic, and pass them to a userspace program named `ape` that
|
||||
acts as an interpreter. In such environments, the need sometimes arises
|
||||
to be able to test that the `/bin/sh` is working correctly, in which
|
||||
case the `APEDBG='` magic is RECOMMENDED.
|
||||
|
||||
APE interpreters, execve() implementations, and binfmt-misc installs
|
||||
MUST ignore this magic. If necessary, steps can be taken to help files
|
||||
with this magic be passed to `/bin/sh` like a normal shebang-less shell
|
||||
script for execution.
|
||||
|
||||
## Embedded ELF Header
|
||||
|
||||
APE binaries MAY embed an ELF header inside them. Unlike conventional
|
||||
executable file formats, this header is not stored at a fixed offset.
|
||||
It's instead encoded as octal escape codes in a shell script `printf`
|
||||
statement. For example:
|
||||
|
||||
```
|
||||
printf '\177ELF\2\1\1\011\0\0\0\0\0\0\0\0\2\0\076\0\1\0\0\0\166\105\100\000\000\000\000\000\060\013\000\000\000\000\000\000\000\000\000\000\000\000\000\000\165\312\1\1\100\0\070\0\005\000\0\0\000\000\000\000'
|
||||
```
|
||||
|
||||
This `printf` statement MUST appear in the first 8192 bytes of the APE
|
||||
executable, so as to limit how much of the initial portion of a file an
|
||||
intepreter must load.
|
||||
|
||||
Multiple such `printf` statements MAY appear in hte first 8192 bytes, in
|
||||
order to specify multiple architectures. For example, fat binaries built
|
||||
by the `apelink` program (provided by Cosmo Libc) will have two encoded
|
||||
ELF headers, for amd64 and arm64, each of which point into the proper
|
||||
file offsets for their respective native code. Therefore, kernels and
|
||||
interpreters which load the APE format directly MUST check the
|
||||
`e_machine` field of the `Elf64_Ehdr` that's decoded from the octal
|
||||
codes, before accepting a `printf` shell statement as valid.
|
||||
|
||||
These printf statements MUST always use only unescaped ASCII characters
|
||||
or octal escape codes. These printf statements MUST NOT use space saving
|
||||
escape codes such as `\n`. For example, rather than saying `\n` it would
|
||||
be valid to say `\012` instead. It's also valid to say `\12` but only if
|
||||
the encoded characters that follow aren't an octal digit.
|
||||
|
||||
For example, the following algorithm may be used for parsing octal:
|
||||
|
||||
```c
|
||||
static int ape_parse_octal(const unsigned char page[8192], int i, int *pc)
|
||||
{
|
||||
int c;
|
||||
if ('0' <= page[i] && page[i] <= '7') {
|
||||
c = page[i++] - '0';
|
||||
if ('0' <= page[i] && page[i] <= '7') {
|
||||
c *= 8;
|
||||
c += page[i++] - '0';
|
||||
if ('0' <= page[i] && page[i] <= '7') {
|
||||
c *= 8;
|
||||
c += page[i++] - '0';
|
||||
}
|
||||
}
|
||||
*pc = c;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
APE aware interpreters SHOULD only take `e_machine` into consideration.
|
||||
It is the responsibility of the `_start()` function to detect the OS.
|
||||
Therefore, multiple `printf` statements are only embedded in the shell
|
||||
script for different CPU architectures.
|
||||
|
||||
The OS ABI field of an APE embedded `Elf64_Ehdr` SHOULD be set to
|
||||
`ELFOSABI_FREEBSD`, since it's the only UNIX OS APE supports that
|
||||
actually checks the field. However different values MAY be chosen for
|
||||
binaries that don't intend to have FreeBSD in their support vector.
|
||||
|
||||
Counter-intuitively, the ARM64 ELF header is used on the MacOS ARM64
|
||||
platform when loading from fat binaries.
|
||||
|
||||
## Embedded Mach-O Header (x86-64 only)
|
||||
|
||||
APE shell scripts that support MacOS on AMD64 must use the `dd` command
|
||||
in a very specific way to specify how the embedded binary Macho-O header
|
||||
is copied backward to the start of the file. For example:
|
||||
|
||||
```
|
||||
dd if="$o" of="$o" bs=8 skip=433 count=66 conv=notrunc
|
||||
```
|
||||
|
||||
These `dd` statements have traditionally been generated by the GNU as
|
||||
and ld.bfd programs by encoding ASCII into 64-bit linker relocations,
|
||||
which necessitated a fixed width for integer values. It took several
|
||||
iterations over APE's history before we eventually got it right:
|
||||
|
||||
- `arg=" 9293"` is how we originally had ape do it
|
||||
- `arg=$(( 9293))` b/c busybox sh disliked quoted space
|
||||
- `arg=9293 ` is generated by modern apelink program
|
||||
|
||||
Software that parses the APE file format, which needs to extract to be
|
||||
able extract the Macho-O x86-64 header SHOULD support the old binaries
|
||||
that use the previous encodings. To make backwards compatibility simple
|
||||
the following regular expression may be used, which generalizes to all
|
||||
defined formats:
|
||||
|
||||
```c
|
||||
regcomp(&rx,
|
||||
"bs=" // dd block size arg
|
||||
"(['\"] *)?" // #1 optional quote w/ space
|
||||
"(\\$\\(\\( *)?" // #2 optional math w/ space
|
||||
"([[:digit:]]+)" // #3
|
||||
"( *\\)\\))?" // #4 optional math w/ space
|
||||
"( *['\"])?" // #5 optional quote w/ space
|
||||
" +" //
|
||||
"skip=" // dd skip arg
|
||||
"(['\"] *)?" // #6 optional quote w/ space
|
||||
"(\\$\\(\\( *)?" // #7 optional math w/ space
|
||||
"([[:digit:]]+)" // #8
|
||||
"( *\\)\\))?" // #9 optional math w/ space
|
||||
"( *['\"])?" // #10 optional quote w/ space
|
||||
" +" //
|
||||
"count=" // dd count arg
|
||||
"(['\"] *)?" // #11 optional quote w/ space
|
||||
"(\\$\\(\\( *)?" // #12 optional math w/ space
|
||||
"([[:digit:]]+)", // #13
|
||||
REG_EXTENDED);
|
||||
```
|
||||
|
||||
For further details, see the canonical implementation in
|
||||
`cosmopolitan/tool/build/assimilate.c`.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -31,7 +31,7 @@ if [ ! -f /proc/sys/fs/binfmt_misc/status ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! build/bootstrap/echo.com -n; then
|
||||
if ! build/bootstrap/echo -n; then
|
||||
cat <<'EOF' >&2
|
||||
|
||||
ERROR
|
||||
|
||||
@@ -18,7 +18,13 @@ CTL_A_CHECKS = \
|
||||
CTL_A_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
THIRD_PARTY_LIBUNWIND \
|
||||
|
||||
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
|
||||
+20
-24
@@ -11,59 +11,55 @@ 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 pointer = typename Alloc::value_type*;
|
||||
using const_pointer = const typename Alloc::value_type*;
|
||||
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 difference_type = ptrdiff_t;
|
||||
using size_type = size_t;
|
||||
|
||||
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;
|
||||
using propagate_on_container_copy_assignment = ctl::false_type;
|
||||
using propagate_on_container_move_assignment = ctl::true_type;
|
||||
using propagate_on_container_swap = ctl::false_type;
|
||||
using is_always_equal = ctl::true_type;
|
||||
|
||||
template<typename T>
|
||||
using rebind_alloc = typename Alloc::template rebind<T>::other;
|
||||
struct rebind_alloc
|
||||
{
|
||||
using other = typename Alloc::template rebind<T>::other;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using rebind_traits = allocator_traits<rebind_alloc<T>>;
|
||||
using rebind_traits = allocator_traits<typename rebind_alloc<T>::other>;
|
||||
|
||||
__attribute__((__always_inline__)) static pointer allocate(Alloc& a,
|
||||
size_type n)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
static void destroy(Alloc& a, T* p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static size_type max_size(
|
||||
const Alloc& a) noexcept
|
||||
static size_type max_size(const Alloc& a) noexcept
|
||||
{
|
||||
return __PTRDIFF_MAX__ / sizeof(value_type);
|
||||
return a.max_size();
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static Alloc
|
||||
select_on_container_copy_construction(const Alloc& a)
|
||||
static Alloc select_on_container_copy_construction(const Alloc& a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
+6
-2
@@ -37,24 +37,28 @@ struct array
|
||||
constexpr reference at(size_type pos)
|
||||
{
|
||||
if (pos >= N)
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::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");
|
||||
throw ctl::out_of_range();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr reference operator[](size_type pos)
|
||||
{
|
||||
if (pos >= N)
|
||||
__builtin_trap();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference operator[](size_type pos) const
|
||||
{
|
||||
if (pos >= N)
|
||||
__builtin_trap();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class bad_alloc : public exception
|
||||
class bad_alloc : public ctl::exception
|
||||
{
|
||||
public:
|
||||
bad_alloc() noexcept = default;
|
||||
|
||||
+8
-7
@@ -16,15 +16,16 @@ template<typename T>
|
||||
struct decay
|
||||
{
|
||||
private:
|
||||
typedef typename remove_reference<T>::type U;
|
||||
typedef typename ctl::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;
|
||||
typedef typename ctl::conditional<
|
||||
ctl::is_array<U>::value,
|
||||
typename ctl::remove_extent<U>::type*,
|
||||
typename ctl::conditional<ctl::is_function<U>::value,
|
||||
typename ctl::add_pointer<U>::type,
|
||||
typename ctl::remove_cv<U>::type>::type>::type
|
||||
type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
+7
-5
@@ -8,28 +8,30 @@
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIter>
|
||||
constexpr typename iterator_traits<InputIter>::difference_type
|
||||
constexpr typename ctl::iterator_traits<InputIter>::difference_type
|
||||
distance_impl(InputIter first, InputIter last, input_iterator_tag)
|
||||
{
|
||||
typename iterator_traits<InputIter>::difference_type res(0);
|
||||
typename ctl::iterator_traits<InputIter>::difference_type res(0);
|
||||
for (; first != last; ++first)
|
||||
++res;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class RandIter>
|
||||
constexpr typename iterator_traits<RandIter>::difference_type
|
||||
constexpr typename ctl::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
|
||||
constexpr typename ctl::iterator_traits<InputIter>::difference_type
|
||||
distance(InputIter first, InputIter last)
|
||||
{
|
||||
return distance_impl(
|
||||
first, last, typename iterator_traits<InputIter>::iterator_category());
|
||||
first,
|
||||
last,
|
||||
typename ctl::iterator_traits<InputIter>::iterator_category());
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// -*- 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 "dubble.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
const double_conversion::DoubleToStringConverter kDoubleToPrintfG(
|
||||
double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
|
||||
double_conversion::DoubleToStringConverter::NO_TRAILING_ZERO,
|
||||
"inf",
|
||||
"nan",
|
||||
'e',
|
||||
-6,
|
||||
10, // let 32-bit ints be represented without exponent
|
||||
6,
|
||||
0,
|
||||
0);
|
||||
|
||||
} // namespace ctl
|
||||
@@ -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 COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
#define COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
#include "third_party/double-conversion/double-to-string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
@@ -11,10 +11,12 @@ 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;
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// -*- 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 "ios.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
ios::ios(FILE* file) : file_(file)
|
||||
{
|
||||
}
|
||||
|
||||
ios::~ios() = default;
|
||||
|
||||
ios&
|
||||
ios::operator=(ios&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
file_ = other.file_;
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,27 @@
|
||||
// -*-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_IOS_H_
|
||||
#define CTL_IOS_H_
|
||||
#include "ios_base.h"
|
||||
|
||||
struct FILE;
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class ios : public ios_base
|
||||
{
|
||||
public:
|
||||
explicit ios(FILE*);
|
||||
virtual ~ios();
|
||||
|
||||
protected:
|
||||
ios& operator=(ios&&) noexcept;
|
||||
FILE* file_;
|
||||
|
||||
private:
|
||||
ios(const ios&) = delete;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IOS_H_
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
// -*- 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 "ios_base.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
ios_base::ios_base() : state_(goodbit), flags_(skipws | dec)
|
||||
{
|
||||
}
|
||||
|
||||
ios_base::~ios_base() = default;
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::flags() const
|
||||
{
|
||||
return static_cast<ios_base::fmtflags>(flags_);
|
||||
}
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::flags(fmtflags fmtfl)
|
||||
{
|
||||
int old = flags_;
|
||||
flags_ = fmtfl;
|
||||
return static_cast<ios_base::fmtflags>(old);
|
||||
}
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::setf(fmtflags fmtfl)
|
||||
{
|
||||
int old = flags_;
|
||||
flags_ |= fmtfl;
|
||||
return static_cast<ios_base::fmtflags>(old);
|
||||
}
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::setf(fmtflags fmtfl, fmtflags mask)
|
||||
{
|
||||
int old = flags_;
|
||||
flags_ = (flags_ & ~mask) | (fmtfl & mask);
|
||||
return static_cast<ios_base::fmtflags>(old);
|
||||
}
|
||||
|
||||
void
|
||||
ios_base::unsetf(fmtflags mask)
|
||||
{
|
||||
flags_ &= ~mask;
|
||||
}
|
||||
|
||||
ios_base::iostate
|
||||
ios_base::rdstate() const
|
||||
{
|
||||
return static_cast<ios_base::iostate>(state_);
|
||||
}
|
||||
|
||||
void
|
||||
ios_base::clear(int state)
|
||||
{
|
||||
state_ = state;
|
||||
}
|
||||
|
||||
void
|
||||
ios_base::setstate(int state)
|
||||
{
|
||||
state_ |= state;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::good() const
|
||||
{
|
||||
return state_ == goodbit;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::eof() const
|
||||
{
|
||||
return (state_ & eofbit) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::fail() const
|
||||
{
|
||||
return (state_ & (failbit | badbit)) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::bad() const
|
||||
{
|
||||
return (state_ & badbit) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::operator!() const
|
||||
{
|
||||
return fail();
|
||||
}
|
||||
|
||||
ios_base::operator bool() const
|
||||
{
|
||||
return !fail();
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,86 @@
|
||||
// -*-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_IOS_BASE_H_
|
||||
#define CTL_IOS_BASE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class ios_base
|
||||
{
|
||||
public:
|
||||
typedef size_t streamsize;
|
||||
|
||||
enum iostate
|
||||
{
|
||||
goodbit = 0,
|
||||
badbit = 1,
|
||||
failbit = 2,
|
||||
eofbit = 4
|
||||
};
|
||||
|
||||
enum fmtflags
|
||||
{
|
||||
boolalpha = 1 << 0,
|
||||
dec = 1 << 1,
|
||||
fixed = 1 << 2,
|
||||
hex = 1 << 3,
|
||||
internal = 1 << 4,
|
||||
left = 1 << 5,
|
||||
oct = 1 << 6,
|
||||
right = 1 << 7,
|
||||
scientific = 1 << 8,
|
||||
showbase = 1 << 9,
|
||||
showpoint = 1 << 10,
|
||||
showpos = 1 << 11,
|
||||
skipws = 1 << 12,
|
||||
unitbuf = 1 << 13,
|
||||
uppercase = 1 << 14,
|
||||
adjustfield = left | right | internal,
|
||||
basefield = dec | oct | hex,
|
||||
floatfield = scientific | fixed
|
||||
};
|
||||
|
||||
enum openmode
|
||||
{
|
||||
app = 1 << 0,
|
||||
binary = 1 << 1,
|
||||
in = 1 << 2,
|
||||
out = 1 << 3,
|
||||
trunc = 1 << 4,
|
||||
ate = 1 << 5
|
||||
};
|
||||
|
||||
protected:
|
||||
ios_base();
|
||||
virtual ~ios_base();
|
||||
|
||||
int state_;
|
||||
int flags_;
|
||||
|
||||
public:
|
||||
fmtflags flags() const;
|
||||
fmtflags flags(fmtflags);
|
||||
fmtflags setf(fmtflags);
|
||||
fmtflags setf(fmtflags, fmtflags);
|
||||
void unsetf(fmtflags);
|
||||
|
||||
iostate rdstate() const;
|
||||
void clear(int = goodbit);
|
||||
void setstate(int);
|
||||
|
||||
bool good() const;
|
||||
bool eof() const;
|
||||
bool fail() const;
|
||||
bool bad() const;
|
||||
|
||||
bool operator!() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
private:
|
||||
ios_base(const ios_base&) = delete;
|
||||
ios_base& operator=(const ios_base&) = delete;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IOS_BASE_H_
|
||||
@@ -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_IS_ABSTRACT_H_
|
||||
#define CTL_IS_ABSTRACT_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_abstract : public ctl::integral_constant<bool, __is_abstract(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_abstract_v = __is_abstract(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_ABSTRACT_H_
|
||||
+3
-3
@@ -7,15 +7,15 @@
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_array : false_type
|
||||
struct is_array : ctl::false_type
|
||||
{};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct is_array<T[N]> : true_type
|
||||
struct is_array<T[N]> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_array<T[]> : true_type
|
||||
struct is_array<T[]> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -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_IS_BASE_OF_H_
|
||||
#define CTL_IS_BASE_OF_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
struct is_base_of
|
||||
: public ctl::integral_constant<bool, __is_base_of(Base, Derived)>
|
||||
{};
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
inline constexpr bool is_base_of_v = __is_base_of(Base, Derived);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_BASE_OF_H_
|
||||
@@ -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_IS_CLASS_H_
|
||||
#define CTL_IS_CLASS_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_class : public ctl::integral_constant<bool, __is_class(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_class_v = __is_class(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_CLASS_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_IS_CONSTRUCTIBLE_H_
|
||||
#define CTL_IS_CONSTRUCTIBLE_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class _Tp, class... _Args>
|
||||
struct is_constructible
|
||||
: public ctl::integral_constant<bool, __is_constructible(_Tp, _Args...)>
|
||||
{};
|
||||
|
||||
template<class _Tp, class... _Args>
|
||||
inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_CONSTRUCTIBLE_H_
|
||||
@@ -2,7 +2,6 @@
|
||||
// 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"
|
||||
|
||||
@@ -16,7 +15,7 @@ declval() noexcept;
|
||||
namespace detail {
|
||||
|
||||
template<typename From, typename To, typename = void>
|
||||
struct is_convertible_impl : false_type
|
||||
struct is_convertible_impl : ctl::false_type
|
||||
{};
|
||||
|
||||
template<typename From, typename To>
|
||||
@@ -28,15 +27,15 @@ struct is_convertible_impl<From,
|
||||
|
||||
// Handle void types separately
|
||||
template<>
|
||||
struct is_convertible_impl<void, void> : true_type
|
||||
struct is_convertible_impl<void, void> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename To>
|
||||
struct is_convertible_impl<void, To> : false_type
|
||||
struct is_convertible_impl<void, To> : ctl::false_type
|
||||
{};
|
||||
|
||||
template<typename From>
|
||||
struct is_convertible_impl<From, void> : false_type
|
||||
struct is_convertible_impl<From, void> : ctl::false_type
|
||||
{};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -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_IS_EMPTY_H_
|
||||
#define CTL_IS_EMPTY_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_empty : public ctl::integral_constant<bool, __is_empty(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_empty_v = __is_empty(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_EMPTY_H_
|
||||
@@ -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_IS_ENUM_H_
|
||||
#define CTL_IS_ENUM_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_enum : public ctl::integral_constant<bool, __is_enum(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_enum_v = __is_enum(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_ENUM_H_
|
||||
+25
-25
@@ -8,111 +8,111 @@ namespace ctl {
|
||||
|
||||
// Primary template
|
||||
template<class>
|
||||
struct is_function : false_type
|
||||
struct is_function : ctl::false_type
|
||||
{};
|
||||
|
||||
// Specializations for various function types
|
||||
|
||||
// Regular functions
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...)> : true_type
|
||||
struct is_function<Ret(Args...)> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Functions with cv-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const> : true_type
|
||||
struct is_function<Ret(Args...) const> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile> : true_type
|
||||
struct is_function<Ret(Args...) volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile> : true_type
|
||||
struct is_function<Ret(Args...) const volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Functions with ref-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...)&> : true_type
|
||||
struct is_function<Ret(Args...)&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const&> : true_type
|
||||
struct is_function<Ret(Args...) const&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile&> : true_type
|
||||
struct is_function<Ret(Args...) volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile&> : true_type
|
||||
struct is_function<Ret(Args...) const volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) &&> : true_type
|
||||
struct is_function<Ret(Args...) &&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const&&> : true_type
|
||||
struct is_function<Ret(Args...) const&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile&&> : true_type
|
||||
struct is_function<Ret(Args...) volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile&&> : true_type
|
||||
struct is_function<Ret(Args...) const volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Variadic functions
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...)> : true_type
|
||||
struct is_function<Ret(Args..., ...)> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Variadic functions with cv-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const> : true_type
|
||||
struct is_function<Ret(Args..., ...) const> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile> : true_type
|
||||
struct is_function<Ret(Args..., ...) volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile> : true_type
|
||||
struct is_function<Ret(Args..., ...) const volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Variadic functions with ref-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...)&> : true_type
|
||||
struct is_function<Ret(Args..., ...)&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile&> : true_type
|
||||
struct is_function<Ret(Args..., ...) volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) &&> : true_type
|
||||
struct is_function<Ret(Args..., ...) &&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const&&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile&&> : true_type
|
||||
struct is_function<Ret(Args..., ...) volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile&&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
+16
-16
@@ -7,67 +7,67 @@
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_integral : false_type
|
||||
struct is_integral : ctl::false_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<bool> : true_type
|
||||
struct is_integral<bool> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char> : true_type
|
||||
struct is_integral<char> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<signed char> : true_type
|
||||
struct is_integral<signed char> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned char> : true_type
|
||||
struct is_integral<unsigned char> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<short> : true_type
|
||||
struct is_integral<short> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned short> : true_type
|
||||
struct is_integral<unsigned short> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<int> : true_type
|
||||
struct is_integral<int> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned int> : true_type
|
||||
struct is_integral<unsigned int> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<long> : true_type
|
||||
struct is_integral<long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned long> : true_type
|
||||
struct is_integral<unsigned long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<long long> : true_type
|
||||
struct is_integral<long long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned long long> : true_type
|
||||
struct is_integral<unsigned long long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char16_t> : true_type
|
||||
struct is_integral<char16_t> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char32_t> : true_type
|
||||
struct is_integral<char32_t> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<wchar_t> : true_type
|
||||
struct is_integral<wchar_t> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -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_IS_POLYMORPHIC_H_
|
||||
#define CTL_IS_POLYMORPHIC_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_polymorphic : public ctl::integral_constant<bool, __is_polymorphic(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_polymorphic_v = __is_polymorphic(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_POLYMORPHIC_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_IS_STANDARD_LAYOUT_H_
|
||||
#define CTL_IS_STANDARD_LAYOUT_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_standard_layout
|
||||
: public ctl::integral_constant<bool, __is_standard_layout(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_standard_layout_v = __is_standard_layout(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_STANDARD_LAYOUT_H_
|
||||
@@ -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_IS_TRIVIAL_H_
|
||||
#define CTL_IS_TRIVIAL_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_trivial : public ctl::integral_constant<bool, __is_trivial(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_trivial_v = __is_trivial(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_TRIVIAL_H_
|
||||
@@ -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_IS_UNION_H_
|
||||
#define CTL_IS_UNION_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_union : public ctl::integral_constant<bool, __is_union(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_union_v = __is_union(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_UNION_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_IS_VOID_H_
|
||||
#define CTL_IS_VOID_H_
|
||||
#include "integral_constant.h"
|
||||
#include "remove_cv.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename>
|
||||
struct is_void_ : public ctl::false_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_void_<void> : public ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename _Tp>
|
||||
struct is_void : public is_void_<typename ctl::remove_cv<_Tp>::type>::type
|
||||
{};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_VOID_H_
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
// -*- 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 "istream.h"
|
||||
#include "libc/ctype.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "numeric_limits.h"
|
||||
#include "string.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
istream cin(stdin);
|
||||
|
||||
istream::~istream() = default;
|
||||
|
||||
istream::istream(FILE* file) : ios(file), gcount_(0)
|
||||
{
|
||||
}
|
||||
|
||||
istream::istream(istream&& other) noexcept
|
||||
: ios(other.file_), gcount_(other.gcount_)
|
||||
{
|
||||
other.file_ = nullptr;
|
||||
other.gcount_ = 0;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator=(istream&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
ios::operator=(ctl::move(other));
|
||||
gcount_ = other.gcount_;
|
||||
other.gcount_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator>>(char& c)
|
||||
{
|
||||
gcount_ = 0;
|
||||
int ch = fgetc(file_);
|
||||
if (ch == EOF) {
|
||||
setstate(eofbit | failbit);
|
||||
} else {
|
||||
c = static_cast<char>(ch);
|
||||
gcount_ = 1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator>>(int& n)
|
||||
{
|
||||
if (fscanf(file_, "%d", &n) != 1)
|
||||
setstate(failbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator>>(long& n)
|
||||
{
|
||||
if (fscanf(file_, "%ld", &n) != 1)
|
||||
setstate(failbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator>>(double& d)
|
||||
{
|
||||
if (fscanf(file_, "%f", &d) != 1)
|
||||
setstate(failbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator>>(ctl::string& s)
|
||||
{
|
||||
char buffer[1024];
|
||||
if (fscanf(file_, "%1023s", buffer) == 1) {
|
||||
s = buffer;
|
||||
} else {
|
||||
setstate(failbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator>>(bool& b)
|
||||
{
|
||||
char buffer[6];
|
||||
if (fscanf(file_, "%5s", buffer) == 1) {
|
||||
if (strcmp(buffer, "true") == 0 || strcmp(buffer, "1") == 0) {
|
||||
b = true;
|
||||
} else if (strcmp(buffer, "false") == 0 || strcmp(buffer, "0") == 0) {
|
||||
b = false;
|
||||
} else {
|
||||
setstate(failbit);
|
||||
}
|
||||
} else {
|
||||
setstate(failbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::operator>>(istream& (*manip)(istream&))
|
||||
{
|
||||
return manip(*this);
|
||||
}
|
||||
|
||||
int
|
||||
istream::get()
|
||||
{
|
||||
gcount_ = 0;
|
||||
int ch = fgetc(file_);
|
||||
if (ch == EOF) {
|
||||
setstate(eofbit);
|
||||
} else {
|
||||
gcount_ = 1;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::get(char& c)
|
||||
{
|
||||
int ch = get();
|
||||
if (ch != EOF)
|
||||
c = static_cast<char>(ch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::getline(char* s, streamsize n)
|
||||
{
|
||||
return getline(s, n, '\n');
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::getline(char* s, streamsize n, char delim)
|
||||
{
|
||||
gcount_ = 0;
|
||||
if (n <= 0) {
|
||||
setstate(failbit);
|
||||
return *this;
|
||||
}
|
||||
while (gcount_ < n - 1) {
|
||||
int ch = fgetc(file_);
|
||||
if (ch == EOF) {
|
||||
setstate(eofbit);
|
||||
break;
|
||||
}
|
||||
if (ch == delim)
|
||||
break;
|
||||
s[gcount_++] = static_cast<char>(ch);
|
||||
}
|
||||
s[gcount_] = '\0';
|
||||
if (gcount_ == 0)
|
||||
setstate(failbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::read(char* s, streamsize n)
|
||||
{
|
||||
gcount_ = fread(s, 1, n, file_);
|
||||
if (gcount_ < n) {
|
||||
setstate(eofbit);
|
||||
if (gcount_ == 0)
|
||||
setstate(failbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream::streamsize
|
||||
istream::gcount() const
|
||||
{
|
||||
return gcount_;
|
||||
}
|
||||
|
||||
int
|
||||
istream::peek()
|
||||
{
|
||||
int ch = fgetc(file_);
|
||||
if (ch != EOF) {
|
||||
ungetc(ch, file_);
|
||||
} else {
|
||||
setstate(eofbit);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
istream&
|
||||
istream::ignore(streamsize n, int delim)
|
||||
{
|
||||
gcount_ = 0;
|
||||
while (gcount_ < n) {
|
||||
int ch = fgetc(file_);
|
||||
if (ch == EOF) {
|
||||
setstate(eofbit);
|
||||
break;
|
||||
}
|
||||
++gcount_;
|
||||
if (ch == delim)
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
istream&
|
||||
ws(istream& is)
|
||||
{
|
||||
int ch;
|
||||
while ((ch = is.peek()) != EOF && isspace(ch))
|
||||
is.get();
|
||||
return is;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,53 @@
|
||||
// -*-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_ISTREAM_H_
|
||||
#define CTL_ISTREAM_H_
|
||||
#include "ios.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct string;
|
||||
|
||||
class istream : public ios
|
||||
{
|
||||
public:
|
||||
istream() = delete;
|
||||
explicit istream(FILE*);
|
||||
virtual ~istream();
|
||||
|
||||
istream& operator>>(char&);
|
||||
istream& operator>>(int&);
|
||||
istream& operator>>(long&);
|
||||
istream& operator>>(double&);
|
||||
istream& operator>>(bool&);
|
||||
istream& operator>>(ctl::string&);
|
||||
istream& operator>>(istream& (*)(istream&));
|
||||
|
||||
int get();
|
||||
istream& get(char&);
|
||||
istream& getline(char*, streamsize);
|
||||
istream& getline(char*, streamsize, char);
|
||||
istream& read(char*, streamsize);
|
||||
streamsize gcount() const;
|
||||
|
||||
int peek();
|
||||
istream& ignore(streamsize = 1, int = -1);
|
||||
|
||||
istream(istream&&) noexcept;
|
||||
istream& operator=(istream&&) noexcept;
|
||||
|
||||
private:
|
||||
streamsize gcount_;
|
||||
|
||||
istream(const istream&) = delete;
|
||||
istream& operator=(const istream&) = delete;
|
||||
};
|
||||
|
||||
extern istream cin;
|
||||
|
||||
istream&
|
||||
ws(istream& is);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ISTREAM_H_
|
||||
@@ -0,0 +1,222 @@
|
||||
// -*- 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 "istringstream.h"
|
||||
#include "libc/ctype.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
istringstream::istringstream() : buffer_(), read_pos_(0)
|
||||
{
|
||||
}
|
||||
|
||||
istringstream::istringstream(const ctl::string_view& str)
|
||||
: buffer_(str), read_pos_(0)
|
||||
{
|
||||
}
|
||||
|
||||
ctl::string
|
||||
istringstream::str() const
|
||||
{
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
void
|
||||
istringstream::str(const ctl::string& s)
|
||||
{
|
||||
buffer_ = s;
|
||||
read_pos_ = 0;
|
||||
clear();
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(char& c)
|
||||
{
|
||||
if (good() && read_pos_ < buffer_.size()) {
|
||||
c = buffer_[read_pos_++];
|
||||
} else {
|
||||
setstate(ios_base::failbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(char* s)
|
||||
{
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
|
||||
++read_pos_;
|
||||
|
||||
size_t start = read_pos_;
|
||||
while (read_pos_ < buffer_.size() && !isspace(buffer_[read_pos_])) {
|
||||
s[read_pos_ - start] = buffer_[read_pos_];
|
||||
++read_pos_;
|
||||
}
|
||||
s[read_pos_ - start] = '\0';
|
||||
|
||||
if (start == read_pos_) {
|
||||
setstate(ios_base::failbit);
|
||||
} else if (read_pos_ == buffer_.size()) {
|
||||
setstate(ios_base::eofbit);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(ctl::string& s)
|
||||
{
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
s.clear();
|
||||
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
|
||||
++read_pos_;
|
||||
|
||||
while (read_pos_ < buffer_.size() && !isspace(buffer_[read_pos_])) {
|
||||
s.push_back(buffer_[read_pos_]);
|
||||
++read_pos_;
|
||||
}
|
||||
|
||||
if (s.empty()) {
|
||||
setstate(ios_base::failbit);
|
||||
} else if (read_pos_ == buffer_.size()) {
|
||||
setstate(ios_base::eofbit);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
istringstream&
|
||||
istringstream::read_numeric(T& value)
|
||||
{
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
|
||||
++read_pos_;
|
||||
|
||||
// size_t start = read_pos_;
|
||||
bool is_negative = false;
|
||||
if (read_pos_ < buffer_.size() &&
|
||||
(buffer_[read_pos_] == '-' || buffer_[read_pos_] == '+')) {
|
||||
is_negative = (buffer_[read_pos_] == '-');
|
||||
++read_pos_;
|
||||
}
|
||||
|
||||
T result = 0;
|
||||
bool valid = false;
|
||||
while (read_pos_ < buffer_.size() && isdigit(buffer_[read_pos_])) {
|
||||
result = result * 10 + (buffer_[read_pos_] - '0');
|
||||
++read_pos_;
|
||||
valid = true;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
value = is_negative ? -result : result;
|
||||
if (read_pos_ == buffer_.size())
|
||||
setstate(ios_base::eofbit);
|
||||
} else {
|
||||
setstate(ios_base::failbit);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(short& n)
|
||||
{
|
||||
return read_numeric(n);
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(unsigned short& n)
|
||||
{
|
||||
return read_numeric(n);
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(int& n)
|
||||
{
|
||||
return read_numeric(n);
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(unsigned int& n)
|
||||
{
|
||||
return read_numeric(n);
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(long& n)
|
||||
{
|
||||
return read_numeric(n);
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(unsigned long& n)
|
||||
{
|
||||
return read_numeric(n);
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(float& f)
|
||||
{
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
char* end;
|
||||
f = strtof(buffer_.c_str() + read_pos_, &end);
|
||||
|
||||
if (end == buffer_.c_str() + read_pos_) {
|
||||
setstate(ios_base::failbit);
|
||||
} else {
|
||||
read_pos_ = end - buffer_.c_str();
|
||||
if (read_pos_ == buffer_.size())
|
||||
setstate(ios_base::eofbit);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
istringstream&
|
||||
istringstream::operator>>(double& d)
|
||||
{
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
char* end;
|
||||
d = strtod(buffer_.c_str() + read_pos_, &end);
|
||||
|
||||
if (end == buffer_.c_str() + read_pos_) {
|
||||
setstate(ios_base::failbit);
|
||||
} else {
|
||||
read_pos_ = end - buffer_.c_str();
|
||||
if (read_pos_ == buffer_.size())
|
||||
setstate(ios_base::eofbit);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,41 @@
|
||||
// -*-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_ISTRINGSTREAM_H_
|
||||
#define CTL_ISTRINGSTREAM_H_
|
||||
#include "ios_base.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class istringstream : public ios_base
|
||||
{
|
||||
public:
|
||||
istringstream();
|
||||
explicit istringstream(const ctl::string_view&);
|
||||
|
||||
string str() const;
|
||||
void str(const string&);
|
||||
|
||||
istringstream& operator>>(char&);
|
||||
istringstream& operator>>(char*);
|
||||
istringstream& operator>>(ctl::string&);
|
||||
istringstream& operator>>(short&);
|
||||
istringstream& operator>>(unsigned short&);
|
||||
istringstream& operator>>(int&);
|
||||
istringstream& operator>>(unsigned int&);
|
||||
istringstream& operator>>(long&);
|
||||
istringstream& operator>>(unsigned long&);
|
||||
istringstream& operator>>(float&);
|
||||
istringstream& operator>>(double&);
|
||||
|
||||
private:
|
||||
ctl::string buffer_;
|
||||
size_t read_pos_;
|
||||
|
||||
template<typename T>
|
||||
istringstream& read_numeric(T&);
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ISTRINGSTREAM_H_
|
||||
+22
-11
@@ -2,12 +2,33 @@
|
||||
// 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 "iterator.h"
|
||||
#include "utility.h"
|
||||
#include "void_t.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class Iterator>
|
||||
template<typename Iterator, typename = void>
|
||||
struct iterator_traits
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct iterator_traits<T*>
|
||||
{
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
using iterator_category = ctl::random_access_iterator_tag;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
struct iterator_traits<Iterator,
|
||||
ctl::void_t<typename Iterator::iterator_category,
|
||||
typename Iterator::value_type,
|
||||
typename Iterator::difference_type,
|
||||
typename Iterator::pointer,
|
||||
typename Iterator::reference>>
|
||||
{
|
||||
using iterator_category = typename Iterator::iterator_category;
|
||||
using value_type = typename Iterator::value_type;
|
||||
@@ -16,16 +37,6 @@ struct iterator_traits
|
||||
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_
|
||||
@@ -152,12 +152,12 @@ class map
|
||||
|
||||
Value& operator[](const Key& key)
|
||||
{
|
||||
return ((data_.insert(make_pair(key, Value()))).first)->second;
|
||||
return ((data_.insert(ctl::make_pair(key, Value()))).first)->second;
|
||||
}
|
||||
|
||||
Value& operator[](Key&& key)
|
||||
{
|
||||
return ((data_.insert(make_pair(ctl::move(key), Value()))).first)
|
||||
return ((data_.insert(ctl::make_pair(ctl::move(key), Value()))).first)
|
||||
->second;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class map
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ class map
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ class map
|
||||
|
||||
size_type erase(const Key& key)
|
||||
{
|
||||
return data_.erase(make_pair(key, Value()));
|
||||
return data_.erase(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
void swap(map& other) noexcept
|
||||
@@ -259,47 +259,47 @@ class map
|
||||
|
||||
iterator find(const Key& key)
|
||||
{
|
||||
return data_.find(make_pair(key, Value()));
|
||||
return data_.find(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator find(const Key& key) const
|
||||
{
|
||||
return data_.find(make_pair(key, Value()));
|
||||
return data_.find(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
size_type count(const Key& key) const
|
||||
{
|
||||
return data_.count(make_pair(key, Value()));
|
||||
return data_.count(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
iterator lower_bound(const Key& key)
|
||||
{
|
||||
return data_.lower_bound(make_pair(key, Value()));
|
||||
return data_.lower_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const Key& key) const
|
||||
{
|
||||
return data_.lower_bound(make_pair(key, Value()));
|
||||
return data_.lower_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
iterator upper_bound(const Key& key)
|
||||
{
|
||||
return data_.upper_bound(make_pair(key, Value()));
|
||||
return data_.upper_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const Key& key) const
|
||||
{
|
||||
return data_.upper_bound(make_pair(key, Value()));
|
||||
return data_.upper_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
ctl::pair<iterator, iterator> equal_range(const Key& key)
|
||||
{
|
||||
return data_.equal_range(make_pair(key, Value()));
|
||||
return data_.equal_range(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
ctl::pair<const_iterator, const_iterator> equal_range(const Key& key) const
|
||||
{
|
||||
return data_.equal_range(make_pair(key, Value()));
|
||||
return data_.equal_range(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
key_compare key_comp() const
|
||||
|
||||
+8
-4
@@ -11,17 +11,20 @@ class mutex
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
pthread_mutex_init(&m_, nullptr);
|
||||
if (pthread_mutex_init(&m_, nullptr))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&m_);
|
||||
if (pthread_mutex_destroy(&m_))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_);
|
||||
if (pthread_mutex_lock(&m_))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
@@ -31,7 +34,8 @@ class mutex
|
||||
|
||||
void unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_);
|
||||
if (pthread_mutex_unlock(&m_))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
// -*- 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 "ostream.h"
|
||||
#include "dubble.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "string_view.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
ostream cout(stdout);
|
||||
ostream cerr(stderr);
|
||||
|
||||
ostream::~ostream() = default;
|
||||
|
||||
ostream::ostream(FILE* file) : ios(file)
|
||||
{
|
||||
}
|
||||
|
||||
ostream::ostream(ostream&& other) noexcept : ios(other.file_)
|
||||
{
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator=(ostream&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
file_ = other.file_;
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(const char* str)
|
||||
{
|
||||
if (good() && str)
|
||||
if (fputs(str, file_) < 0)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(char c)
|
||||
{
|
||||
if (good())
|
||||
if (fputc(c, file_) == EOF)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(int n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
FormatInt32(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(unsigned n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
FormatUint32(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
FormatInt64(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(unsigned long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
FormatUint64(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(float f)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortestSingle(f, &b);
|
||||
b.Finalize();
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(double d)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortest(d, &b);
|
||||
b.Finalize();
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(const string_view& s)
|
||||
{
|
||||
if (good() && s.size())
|
||||
if (!fwrite(s.data(), s.size(), 1, file_))
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(bool b)
|
||||
{
|
||||
if (good()) {
|
||||
const char* value =
|
||||
(flags() & boolalpha) ? (b ? "true" : "false") : (b ? "1" : "0");
|
||||
if (fputs(value, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(ostream& (*manip)(ostream&))
|
||||
{
|
||||
return manip(*this);
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::put(char c)
|
||||
{
|
||||
if (good())
|
||||
if (fputc(c, file_) == EOF)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::write(const char* s, streamsize n)
|
||||
{
|
||||
if (good())
|
||||
if (fwrite(s, 1, n, file_) != static_cast<size_t>(n))
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::flush()
|
||||
{
|
||||
if (good())
|
||||
if (fflush(file_) != 0)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
endl(ostream& os)
|
||||
{
|
||||
return os.put('\n').flush();
|
||||
}
|
||||
|
||||
ostream&
|
||||
ends(ostream& os)
|
||||
{
|
||||
return os.put('\0');
|
||||
}
|
||||
|
||||
ostream&
|
||||
flush(ostream& os)
|
||||
{
|
||||
return os.flush();
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,56 @@
|
||||
// -*-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_OSTREAM_H_
|
||||
#define CTL_OSTREAM_H_
|
||||
#include "ios.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct string_view;
|
||||
|
||||
class ostream : public ios
|
||||
{
|
||||
public:
|
||||
ostream() = delete;
|
||||
explicit ostream(FILE*);
|
||||
virtual ~ostream();
|
||||
|
||||
ostream& operator<<(const char*);
|
||||
ostream& operator<<(bool);
|
||||
ostream& operator<<(char);
|
||||
ostream& operator<<(int);
|
||||
ostream& operator<<(unsigned);
|
||||
ostream& operator<<(long);
|
||||
ostream& operator<<(unsigned long);
|
||||
ostream& operator<<(float);
|
||||
ostream& operator<<(double);
|
||||
ostream& operator<<(const ctl::string_view&);
|
||||
ostream& operator<<(ostream& (*)(ostream&));
|
||||
|
||||
ostream& put(char);
|
||||
ostream& write(const char*, streamsize);
|
||||
ostream& flush();
|
||||
|
||||
ostream(ostream&&) noexcept;
|
||||
ostream& operator=(ostream&&) noexcept;
|
||||
|
||||
private:
|
||||
ostream(const ostream&) = delete;
|
||||
ostream& operator=(const ostream&) = delete;
|
||||
};
|
||||
|
||||
extern ostream cout;
|
||||
extern ostream cerr;
|
||||
|
||||
ostream&
|
||||
endl(ostream&);
|
||||
|
||||
ostream&
|
||||
ends(ostream&);
|
||||
|
||||
ostream&
|
||||
flush(ostream&);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_OSTREAM_H_
|
||||
@@ -0,0 +1,150 @@
|
||||
// -*- 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 "ostringstream.h"
|
||||
#include "dubble.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
ostringstream::ostringstream() : buffer_(), write_pos_(0)
|
||||
{
|
||||
}
|
||||
|
||||
ostringstream::ostringstream(const string_view& str)
|
||||
: buffer_(str), write_pos_(0)
|
||||
{
|
||||
}
|
||||
|
||||
string
|
||||
ostringstream::str() const
|
||||
{
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
void
|
||||
ostringstream::str(const string& s)
|
||||
{
|
||||
buffer_ = s;
|
||||
write_pos_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ostringstream::clear()
|
||||
{
|
||||
ios_base::clear();
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(char c)
|
||||
{
|
||||
if (good()) {
|
||||
if (write_pos_ < buffer_.size()) {
|
||||
buffer_[write_pos_++] = c;
|
||||
} else {
|
||||
buffer_.push_back(c);
|
||||
++write_pos_;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(const string_view& s)
|
||||
{
|
||||
if (good()) {
|
||||
if (write_pos_ + s.size() <= buffer_.size()) {
|
||||
buffer_.replace(write_pos_, s.size(), s);
|
||||
} else {
|
||||
buffer_.replace(write_pos_, buffer_.size() - write_pos_, s);
|
||||
buffer_.append(s.substr(buffer_.size() - write_pos_));
|
||||
}
|
||||
write_pos_ += s.size();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(int n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
*this << string_view(buf, FormatInt32(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(unsigned n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
*this << string_view(buf, FormatUint32(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
*this << string_view(buf, FormatInt64(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(unsigned long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
*this << string_view(buf, FormatUint64(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(float f)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortestSingle(f, &b);
|
||||
b.Finalize();
|
||||
*this << string_view(buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(double d)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortest(d, &b);
|
||||
b.Finalize();
|
||||
*this << string_view(buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,36 @@
|
||||
// -*-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_OSTRINGSTREAM_H_
|
||||
#define CTL_OSTRINGSTREAM_H_
|
||||
#include "ios_base.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class ostringstream : public ios_base
|
||||
{
|
||||
public:
|
||||
ostringstream();
|
||||
explicit ostringstream(const ctl::string_view&);
|
||||
|
||||
ctl::string str() const;
|
||||
void str(const ctl::string& s);
|
||||
void clear();
|
||||
|
||||
ostringstream& operator<<(char);
|
||||
ostringstream& operator<<(const ctl::string_view&);
|
||||
ostringstream& operator<<(int);
|
||||
ostringstream& operator<<(unsigned int);
|
||||
ostringstream& operator<<(long);
|
||||
ostringstream& operator<<(unsigned long);
|
||||
ostringstream& operator<<(float);
|
||||
ostringstream& operator<<(double);
|
||||
|
||||
private:
|
||||
ctl::string buffer_;
|
||||
size_t write_pos_;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_OSTRINGSTREAM_H_
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class out_of_range : public exception
|
||||
class out_of_range : public ctl::exception
|
||||
{
|
||||
public:
|
||||
out_of_range() noexcept = default;
|
||||
|
||||
@@ -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_REQUIRE_INPUT_ITERATOR_H_
|
||||
#define CTL_REQUIRE_INPUT_ITERATOR_H_
|
||||
#include "enable_if.h"
|
||||
#include "is_convertible.h"
|
||||
#include "iterator.h"
|
||||
#include "iterator_traits.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename InputIt>
|
||||
using require_input_iterator = typename ctl::enable_if<
|
||||
ctl::is_convertible<typename ctl::iterator_traits<InputIt>::iterator_category,
|
||||
ctl::input_iterator_tag>::value>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_REQUIRE_INPUT_ITERATOR_H_ */
|
||||
@@ -13,11 +13,12 @@ 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;
|
||||
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 = typename ctl::iterator_traits<Iterator>::pointer;
|
||||
using reference = typename ctl::iterator_traits<Iterator>::reference;
|
||||
|
||||
constexpr reverse_iterator() : current()
|
||||
{
|
||||
|
||||
@@ -8,23 +8,39 @@
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Key, typename Compare = less<Key>>
|
||||
template<typename Key, typename Compare = ctl::less<Key>>
|
||||
class set
|
||||
{
|
||||
struct rbtree
|
||||
{
|
||||
rbtree* left;
|
||||
uintptr_t left_;
|
||||
rbtree* right;
|
||||
rbtree* parent;
|
||||
bool is_red;
|
||||
Key value;
|
||||
|
||||
rbtree* left() const
|
||||
{
|
||||
return (rbtree*)(left_ & -2);
|
||||
}
|
||||
|
||||
void left(rbtree* val)
|
||||
{
|
||||
left_ = (uintptr_t)val | (left_ & 1);
|
||||
}
|
||||
|
||||
bool is_red() const
|
||||
{
|
||||
return left_ & 1;
|
||||
}
|
||||
|
||||
void is_red(bool val)
|
||||
{
|
||||
left_ &= -2;
|
||||
left_ |= val;
|
||||
}
|
||||
|
||||
rbtree(const Key& val)
|
||||
: left(nullptr)
|
||||
, right(nullptr)
|
||||
, parent(nullptr)
|
||||
, is_red(true)
|
||||
, value(val)
|
||||
: left_(1), right(nullptr), parent(nullptr), value(val)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -85,14 +101,14 @@ class set
|
||||
{
|
||||
if (node_ == nullptr)
|
||||
__builtin_trap();
|
||||
if (node_->left) {
|
||||
node_ = rightmost(node_->left);
|
||||
if (node_->left()) {
|
||||
node_ = rightmost(node_->left());
|
||||
} else {
|
||||
node_type* parent = node_->parent;
|
||||
for (;;) {
|
||||
if (parent == nullptr)
|
||||
break;
|
||||
if (node_ == parent->left) {
|
||||
if (node_ == parent->left()) {
|
||||
node_ = parent;
|
||||
parent = parent->parent;
|
||||
} else {
|
||||
@@ -161,11 +177,11 @@ class set
|
||||
|
||||
reverse_iterator& operator++()
|
||||
{
|
||||
if (node_->left) {
|
||||
node_ = rightmost(node_->left);
|
||||
if (node_->left()) {
|
||||
node_ = rightmost(node_->left());
|
||||
} else {
|
||||
node_type* parent = node_->parent;
|
||||
while (parent && node_ == parent->left) {
|
||||
while (parent && node_ == parent->left()) {
|
||||
node_ = parent;
|
||||
parent = parent->parent;
|
||||
}
|
||||
@@ -381,12 +397,12 @@ class set
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
pair<iterator, bool> insert(value_type&& value)
|
||||
ctl::pair<iterator, bool> insert(value_type&& value)
|
||||
{
|
||||
return insert_node(new node_type(ctl::move(value)));
|
||||
}
|
||||
|
||||
pair<iterator, bool> insert(const value_type& value)
|
||||
ctl::pair<iterator, bool> insert(const value_type& value)
|
||||
{
|
||||
return insert_node(new node_type(value));
|
||||
}
|
||||
@@ -415,7 +431,7 @@ class set
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
pair<iterator, bool> emplace(Args&&... args)
|
||||
ctl::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
value_type value(ctl::forward<Args>(args)...);
|
||||
return insert(ctl::move(value));
|
||||
@@ -451,12 +467,13 @@ class set
|
||||
ctl::swap(size_, other.size_);
|
||||
}
|
||||
|
||||
pair<iterator, iterator> equal_range(const key_type& key)
|
||||
ctl::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
|
||||
ctl::pair<const_iterator, const_iterator> equal_range(
|
||||
const key_type& key) const
|
||||
{
|
||||
return { const_iterator(get_floor(key)),
|
||||
const_iterator(get_ceiling(key)) };
|
||||
@@ -507,7 +524,7 @@ class set
|
||||
{
|
||||
size_type count = 0;
|
||||
if (root_ != nullptr) {
|
||||
if (root_->is_red)
|
||||
if (root_->is_red())
|
||||
// ILLEGAL TREE: root node must be black
|
||||
__builtin_trap();
|
||||
int black_height = -1;
|
||||
@@ -522,8 +539,8 @@ class set
|
||||
private:
|
||||
static node_type* leftmost(node_type* node) noexcept
|
||||
{
|
||||
while (node && node->left)
|
||||
node = node->left;
|
||||
while (node && node->left())
|
||||
node = node->left();
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -534,35 +551,35 @@ class set
|
||||
return node;
|
||||
}
|
||||
|
||||
static void clearer(node_type* node) noexcept
|
||||
static optimizesize void clearer(node_type* node) noexcept
|
||||
{
|
||||
node_type* right;
|
||||
for (; node; node = right) {
|
||||
right = node->right;
|
||||
clearer(node->left);
|
||||
clearer(node->left());
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
static node_type* copier(const node_type* node)
|
||||
static optimizesize 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->left(copier(node->left()));
|
||||
new_node->right = copier(node->right);
|
||||
if (new_node->left)
|
||||
new_node->left->parent = new_node;
|
||||
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)
|
||||
static optimizesize size_type tally(const node_type* node)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return 0;
|
||||
return 1 + tally(node->left) + tally(node->right);
|
||||
return 1 + tally(node->left()) + tally(node->right);
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
@@ -571,7 +588,7 @@ class set
|
||||
node_type* current = root_;
|
||||
while (current != nullptr) {
|
||||
if (comp_(key, current->value)) {
|
||||
current = current->left;
|
||||
current = current->left();
|
||||
} else if (comp_(current->value, key)) {
|
||||
current = current->right;
|
||||
} else {
|
||||
@@ -589,7 +606,7 @@ class set
|
||||
while (current != nullptr) {
|
||||
if (!comp_(current->value, key)) {
|
||||
result = current;
|
||||
current = current->left;
|
||||
current = current->left();
|
||||
} else {
|
||||
current = current->right;
|
||||
}
|
||||
@@ -605,7 +622,7 @@ class set
|
||||
while (current != nullptr) {
|
||||
if (comp_(key, current->value)) {
|
||||
result = current;
|
||||
current = current->left;
|
||||
current = current->left();
|
||||
} else {
|
||||
current = current->right;
|
||||
}
|
||||
@@ -613,11 +630,11 @@ class set
|
||||
return result;
|
||||
}
|
||||
|
||||
pair<iterator, bool> insert_node(node_type* node)
|
||||
optimizesize ctl::pair<iterator, bool> insert_node(node_type* node)
|
||||
{
|
||||
if (root_ == nullptr) {
|
||||
root_ = node;
|
||||
root_->is_red = false;
|
||||
root_->is_red(false);
|
||||
size_++;
|
||||
return { iterator(root_), true };
|
||||
}
|
||||
@@ -626,7 +643,7 @@ class set
|
||||
while (current != nullptr) {
|
||||
parent = current;
|
||||
if (comp_(node->value, current->value)) {
|
||||
current = current->left;
|
||||
current = current->left();
|
||||
} else if (comp_(current->value, node->value)) {
|
||||
current = current->right;
|
||||
} else {
|
||||
@@ -635,7 +652,7 @@ class set
|
||||
}
|
||||
}
|
||||
if (comp_(node->value, parent->value)) {
|
||||
parent->left = node;
|
||||
parent->left(node);
|
||||
} else {
|
||||
parent->right = node;
|
||||
}
|
||||
@@ -645,23 +662,23 @@ class set
|
||||
return { iterator(node), true };
|
||||
}
|
||||
|
||||
void erase_node(node_type* node)
|
||||
optimizesize 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) {
|
||||
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 = node->left();
|
||||
transplant(node, node->left());
|
||||
x_parent = node->parent;
|
||||
} else {
|
||||
y = leftmost(node->right);
|
||||
y_original_color = y->is_red;
|
||||
y_original_color = y->is_red();
|
||||
x = y->right;
|
||||
if (y->parent == node) {
|
||||
if (x)
|
||||
@@ -674,9 +691,9 @@ class set
|
||||
x_parent = y->parent;
|
||||
}
|
||||
transplant(node, y);
|
||||
y->left = node->left;
|
||||
y->left->parent = y;
|
||||
y->is_red = node->is_red;
|
||||
y->left(node->left());
|
||||
y->left()->parent = y;
|
||||
y->is_red(node->is_red());
|
||||
}
|
||||
if (!y_original_color)
|
||||
rebalance_after_erase(x, x_parent);
|
||||
@@ -684,28 +701,28 @@ class set
|
||||
--size_;
|
||||
}
|
||||
|
||||
void left_rotate(node_type* x)
|
||||
optimizesize void left_rotate(node_type* x)
|
||||
{
|
||||
node_type* y = x->right;
|
||||
x->right = y->left;
|
||||
if (y->left != nullptr)
|
||||
y->left->parent = x;
|
||||
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 if (x == x->parent->left()) {
|
||||
x->parent->left(y);
|
||||
} else {
|
||||
x->parent->right = y;
|
||||
}
|
||||
y->left = x;
|
||||
y->left(x);
|
||||
x->parent = y;
|
||||
}
|
||||
|
||||
void right_rotate(node_type* y)
|
||||
optimizesize void right_rotate(node_type* y)
|
||||
{
|
||||
node_type* x = y->left;
|
||||
y->left = x->right;
|
||||
node_type* x = y->left();
|
||||
y->left(x->right);
|
||||
if (x->right != nullptr)
|
||||
x->right->parent = y;
|
||||
x->parent = y->parent;
|
||||
@@ -714,18 +731,18 @@ class set
|
||||
} else if (y == y->parent->right) {
|
||||
y->parent->right = x;
|
||||
} else {
|
||||
y->parent->left = x;
|
||||
y->parent->left(x);
|
||||
}
|
||||
x->right = y;
|
||||
y->parent = x;
|
||||
}
|
||||
|
||||
void transplant(node_type* u, node_type* v)
|
||||
optimizesize 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 if (u == u->parent->left()) {
|
||||
u->parent->left(v);
|
||||
} else {
|
||||
u->parent->right = v;
|
||||
}
|
||||
@@ -733,10 +750,10 @@ class set
|
||||
v->parent = u->parent;
|
||||
}
|
||||
|
||||
void checker(const node_type* node,
|
||||
const node_type* parent,
|
||||
int black_count,
|
||||
int& black_height) const
|
||||
optimizesize 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
|
||||
@@ -752,117 +769,121 @@ class set
|
||||
// ILLEGAL TREE: Parent link is incorrect
|
||||
__builtin_trap();
|
||||
if (parent) {
|
||||
if (parent->left == node && !comp_(node->value, parent->value))
|
||||
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) {
|
||||
if (!node->is_red()) {
|
||||
black_count++;
|
||||
} else if (parent != nullptr && parent->is_red) {
|
||||
} 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->left(), node, black_count, black_height);
|
||||
checker(node->right, node, black_count, black_height);
|
||||
}
|
||||
|
||||
void rebalance_after_insert(node_type* node)
|
||||
optimizesize 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->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;
|
||||
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;
|
||||
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_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) {
|
||||
if (node == node->parent->left()) {
|
||||
node = node->parent;
|
||||
right_rotate(node);
|
||||
}
|
||||
node->parent->is_red = false;
|
||||
node->parent->parent->is_red = true;
|
||||
node->parent->is_red(false);
|
||||
node->parent->parent->is_red(true);
|
||||
left_rotate(node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
root_->is_red = false;
|
||||
root_->is_red(false);
|
||||
}
|
||||
|
||||
void rebalance_after_erase(node_type* node, node_type* parent)
|
||||
optimizesize void rebalance_after_erase(node_type* node, node_type* parent)
|
||||
{
|
||||
while (node != root_ && (node == nullptr || !node->is_red)) {
|
||||
if (node == parent->left) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
node_type* sibling = parent->left();
|
||||
if (sibling->is_red()) {
|
||||
sibling->is_red(false);
|
||||
parent->is_red(true);
|
||||
right_rotate(parent);
|
||||
sibling = parent->left;
|
||||
sibling = parent->left();
|
||||
}
|
||||
if ((sibling->right == nullptr || !sibling->right->is_red) &&
|
||||
(sibling->left == nullptr || !sibling->left->is_red)) {
|
||||
sibling->is_red = true;
|
||||
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;
|
||||
if (sibling->left() == nullptr ||
|
||||
!sibling->left()->is_red()) {
|
||||
sibling->right->is_red(false);
|
||||
sibling->is_red(true);
|
||||
left_rotate(sibling);
|
||||
sibling = parent->left;
|
||||
sibling = parent->left();
|
||||
}
|
||||
sibling->is_red = parent->is_red;
|
||||
parent->is_red = false;
|
||||
sibling->left->is_red = false;
|
||||
sibling->is_red(parent->is_red());
|
||||
parent->is_red(false);
|
||||
sibling->left()->is_red(false);
|
||||
right_rotate(parent);
|
||||
node = root_;
|
||||
break;
|
||||
@@ -870,7 +891,7 @@ class set
|
||||
}
|
||||
}
|
||||
if (node != nullptr)
|
||||
node->is_red = false;
|
||||
node->is_red(false);
|
||||
}
|
||||
|
||||
node_type* root_;
|
||||
@@ -878,7 +899,7 @@ class set
|
||||
Compare comp_;
|
||||
};
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
template<class Key, typename Compare = ctl::less<Key>>
|
||||
bool
|
||||
operator==(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
@@ -893,7 +914,7 @@ operator==(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
template<class Key, typename Compare = ctl::less<Key>>
|
||||
bool
|
||||
operator<(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
@@ -908,35 +929,35 @@ operator<(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
return i == lhs.end() && j != rhs.end();
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
template<class Key, typename Compare = ctl::less<Key>>
|
||||
bool
|
||||
operator!=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
template<class Key, typename Compare = ctl::less<Key>>
|
||||
bool
|
||||
operator<=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
template<class Key, typename Compare = ctl::less<Key>>
|
||||
bool
|
||||
operator>(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
template<class Key, typename Compare = ctl::less<Key>>
|
||||
bool
|
||||
operator>=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<class Key, typename Compare = less<Key>>
|
||||
template<class Key, typename Compare = ctl::less<Key>>
|
||||
void
|
||||
swap(set<Key, Compare>& lhs, set<Key, Compare>& rhs) noexcept;
|
||||
|
||||
|
||||
+80
-25
@@ -9,7 +9,7 @@ namespace ctl {
|
||||
|
||||
class string;
|
||||
|
||||
string strcat(string_view, string_view) noexcept __wur;
|
||||
ctl::string strcat(ctl::string_view, ctl::string_view) noexcept __wur;
|
||||
|
||||
namespace __ {
|
||||
|
||||
@@ -66,7 +66,7 @@ class string
|
||||
*(((size_t*)blob) + 2) = __::sso_max << (sizeof(size_t) - 1) * 8;
|
||||
}
|
||||
|
||||
string(const string_view s) noexcept
|
||||
string(const ctl::string_view s) noexcept
|
||||
{
|
||||
if (s.n <= __::sso_max) {
|
||||
__builtin_memcpy(blob, s.p, s.n);
|
||||
@@ -89,7 +89,7 @@ class string
|
||||
}
|
||||
|
||||
string(const char* const p) noexcept
|
||||
: string(string_view(p, __builtin_strlen(p)))
|
||||
: string(ctl::string_view(p, __builtin_strlen(p)))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ class string
|
||||
}
|
||||
|
||||
string(const char* const p, const size_t n) noexcept
|
||||
: string(string_view(p, n))
|
||||
: string(ctl::string_view(p, n))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -125,17 +125,17 @@ class string
|
||||
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& insert(size_t, ctl::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;
|
||||
string& replace(size_t, size_t, ctl::string_view) noexcept;
|
||||
bool operator==(ctl::string_view) const noexcept;
|
||||
bool operator!=(ctl::string_view) const noexcept;
|
||||
bool contains(ctl::string_view) const noexcept;
|
||||
bool ends_with(ctl::string_view) const noexcept;
|
||||
bool starts_with(ctl::string_view) const noexcept;
|
||||
size_t find(char, size_t = 0) const noexcept;
|
||||
size_t find(string_view, size_t = 0) const noexcept;
|
||||
size_t find(ctl::string_view, size_t = 0) const noexcept;
|
||||
|
||||
void swap(string& s) noexcept
|
||||
{
|
||||
@@ -302,14 +302,14 @@ class string
|
||||
append(ch);
|
||||
}
|
||||
|
||||
void append(const string_view s) noexcept
|
||||
void append(const ctl::string_view s) noexcept
|
||||
{
|
||||
append(s.p, s.n);
|
||||
}
|
||||
|
||||
operator string_view() const noexcept
|
||||
operator ctl::string_view() const noexcept
|
||||
{
|
||||
return string_view(data(), size());
|
||||
return ctl::string_view(data(), size());
|
||||
}
|
||||
|
||||
string& operator=(const char* s) noexcept
|
||||
@@ -319,7 +319,7 @@ class string
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator=(const string_view s) noexcept
|
||||
string& operator=(const ctl::string_view s) noexcept
|
||||
{
|
||||
clear();
|
||||
append(s);
|
||||
@@ -332,38 +332,66 @@ class string
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator+=(const string_view s) noexcept
|
||||
string& operator+=(const char* s) noexcept
|
||||
{
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string operator+(const string_view s) const noexcept
|
||||
string& operator+=(const ctl::string s) noexcept
|
||||
{
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator+=(const ctl::string_view s) noexcept
|
||||
{
|
||||
append(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string operator+(const char c) const noexcept
|
||||
{
|
||||
char s[2] = { c };
|
||||
return strcat(*this, s);
|
||||
}
|
||||
|
||||
string operator+(const char* s) const noexcept
|
||||
{
|
||||
return strcat(*this, s);
|
||||
}
|
||||
|
||||
int compare(const string_view s) const noexcept
|
||||
string operator+(const string& s) const noexcept
|
||||
{
|
||||
return strcat(*this, s);
|
||||
}
|
||||
|
||||
string operator+(const ctl::string_view s) const noexcept
|
||||
{
|
||||
return strcat(*this, s);
|
||||
}
|
||||
|
||||
int compare(const ctl::string_view s) const noexcept
|
||||
{
|
||||
return strcmp(*this, s);
|
||||
}
|
||||
|
||||
bool operator<(const string_view s) const noexcept
|
||||
bool operator<(const ctl::string_view s) const noexcept
|
||||
{
|
||||
return compare(s) < 0;
|
||||
}
|
||||
|
||||
bool operator<=(const string_view s) const noexcept
|
||||
bool operator<=(const ctl::string_view s) const noexcept
|
||||
{
|
||||
return compare(s) <= 0;
|
||||
}
|
||||
|
||||
bool operator>(const string_view s) const noexcept
|
||||
bool operator>(const ctl::string_view s) const noexcept
|
||||
{
|
||||
return compare(s) > 0;
|
||||
}
|
||||
|
||||
bool operator>=(const string_view s) const noexcept
|
||||
bool operator>=(const ctl::string_view s) const noexcept
|
||||
{
|
||||
return compare(s) >= 0;
|
||||
}
|
||||
@@ -371,7 +399,7 @@ class string
|
||||
private:
|
||||
void destroy_big() noexcept;
|
||||
void init_big(const string&) noexcept;
|
||||
void init_big(string_view) noexcept;
|
||||
void init_big(ctl::string_view) noexcept;
|
||||
void init_big(size_t, char) noexcept;
|
||||
|
||||
__attribute__((__always_inline__)) bool isbig() const noexcept
|
||||
@@ -395,7 +423,7 @@ class string
|
||||
__b.c = c2 | ~__::big_mask;
|
||||
}
|
||||
|
||||
friend string strcat(string_view, string_view) noexcept;
|
||||
friend string strcat(ctl::string_view, ctl::string_view) noexcept;
|
||||
|
||||
union
|
||||
{
|
||||
@@ -409,6 +437,33 @@ static_assert(sizeof(string) == __::string_size);
|
||||
static_assert(sizeof(__::small_string) == __::string_size);
|
||||
static_assert(sizeof(__::big_string) == __::string_size);
|
||||
|
||||
ctl::string
|
||||
to_string(int) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(long) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(long long) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(unsigned) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(unsigned long) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(unsigned long long) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(float) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(double) noexcept;
|
||||
|
||||
ctl::string
|
||||
to_string(long double) noexcept;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
// -*-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_
|
||||
#ifndef CTL_STRINGVIEW_H_
|
||||
#define CTL_STRINGVIEW_H_
|
||||
#include "utility.h"
|
||||
|
||||
namespace ctl {
|
||||
@@ -157,4 +157,4 @@ struct string_view
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_STRINGVIEW_H_
|
||||
#endif // CTL_STRINGVIEW_H_
|
||||
@@ -0,0 +1,109 @@
|
||||
// -*- 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 "dubble.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/math.h"
|
||||
#include "string.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
string
|
||||
to_string(int value) noexcept
|
||||
{
|
||||
char buf[12];
|
||||
return { buf, FormatInt32(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(unsigned value) noexcept
|
||||
{
|
||||
char buf[12];
|
||||
return { buf, FormatUint32(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatInt64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(unsigned long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatUint64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(long long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatInt64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(unsigned long long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatUint64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(float value) noexcept
|
||||
{
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortestSingle(value, &b);
|
||||
b.Finalize();
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
string
|
||||
to_string(double value) noexcept
|
||||
{
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortest(value, &b);
|
||||
b.Finalize();
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
string
|
||||
to_string(long double value) noexcept
|
||||
{
|
||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
return to_string((double)value);
|
||||
#else
|
||||
char buf[128];
|
||||
#if LDBL_MANT_DIG == 113
|
||||
g_Qfmt_p(buf, &value, 16, 128, NIK(2, 0, 0));
|
||||
#elif LDBL_MANT_DIG == 64
|
||||
g_xfmt_p(buf, &value, 16, 128, NIK(2, 0, 0));
|
||||
#else
|
||||
#error "unsupported long double"
|
||||
#endif
|
||||
return string(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
// -*-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_
|
||||
#ifndef CTL_UTILITY_H_
|
||||
#define CTL_UTILITY_H_
|
||||
#include "remove_reference.h"
|
||||
|
||||
namespace ctl {
|
||||
@@ -66,4 +66,4 @@ declval() noexcept;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_UTILITY_H_
|
||||
#endif // CTL_UTILITY_H_
|
||||
+15
-9
@@ -15,6 +15,7 @@
|
||||
#include "move_backward.h"
|
||||
#include "move_iterator.h"
|
||||
#include "out_of_range.h"
|
||||
#include "require_input_iterator.h"
|
||||
#include "reverse_iterator.h"
|
||||
#include "uninitialized_fill.h"
|
||||
#include "uninitialized_fill_n.h"
|
||||
@@ -65,7 +66,7 @@ class vector
|
||||
resize(count);
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
template<class InputIt, typename = ctl::require_input_iterator<InputIt>>
|
||||
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator())
|
||||
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
|
||||
{
|
||||
@@ -173,7 +174,7 @@ class vector
|
||||
size_ = count;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
template<class InputIt, typename = ctl::require_input_iterator<InputIt>>
|
||||
void assign(InputIt first, InputIt last)
|
||||
{
|
||||
clear();
|
||||
@@ -189,24 +190,28 @@ class vector
|
||||
reference at(size_type pos)
|
||||
{
|
||||
if (pos >= size_)
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= size_)
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
reference operator[](size_type pos)
|
||||
{
|
||||
if (pos >= size_)
|
||||
__builtin_trap();
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
const_reference operator[](size_type pos) const
|
||||
{
|
||||
if (pos >= size_)
|
||||
__builtin_trap();
|
||||
return data_[pos];
|
||||
}
|
||||
|
||||
@@ -368,7 +373,7 @@ class vector
|
||||
return it;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
template<class InputIt, typename = ctl::require_input_iterator<InputIt>>
|
||||
iterator insert(const_iterator pos, InputIt first, InputIt last)
|
||||
{
|
||||
difference_type count = ctl::distance(first, last);
|
||||
@@ -406,16 +411,17 @@ class vector
|
||||
return erase(pos, pos + 1);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
constexpr 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 (iterator move_it = it + count; move_it != end(); ++move_it, ++it)
|
||||
*it = ctl::move(*move_it);
|
||||
for (difference_type i = 0; i < count; ++i)
|
||||
ctl::allocator_traits<Allocator>::destroy(alloc_, end() - i - 1);
|
||||
size_ -= count;
|
||||
return it;
|
||||
return begin() + index;
|
||||
}
|
||||
|
||||
void push_back(const T& value)
|
||||
@@ -519,7 +525,7 @@ class vector
|
||||
capacity_ = new_capacity;
|
||||
}
|
||||
|
||||
Allocator alloc_;
|
||||
[[no_unique_address]] Allocator alloc_;
|
||||
pointer data_;
|
||||
size_type size_;
|
||||
size_type capacity_;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/safemacros.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "dsp/tty/ttyrgb.h"
|
||||
#include "dsp/tty/windex.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
@@ -39,6 +39,7 @@ EXAMPLES_BINS = \
|
||||
$(EXAMPLES_COMS:%=%.dbg)
|
||||
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
CTL \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include <cosmo.h>
|
||||
#include <math.h>
|
||||
|
||||
void crash(long x0, long x1, long x2, //
|
||||
double v0, double v1, double v2) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include "libc/mem/leaks.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* @fileoverview greenbean lightweight threaded web server
|
||||
@@ -288,10 +289,11 @@ int main(int argc, char *argv[]) {
|
||||
// print all the ips that 0.0.0.0 would bind
|
||||
// Cosmo's GetHostIps() API is much easier than ioctl(SIOCGIFCONF)
|
||||
uint32_t *hostips;
|
||||
for (hostips = gc(GetHostIps()), i = 0; hostips[i]; ++i) {
|
||||
for (hostips = GetHostIps(), i = 0; hostips[i]; ++i) {
|
||||
kprintf("listening on http://%hhu.%hhu.%hhu.%hhu:%hu\n", hostips[i] >> 24,
|
||||
hostips[i] >> 16, hostips[i] >> 8, hostips[i], PORT);
|
||||
}
|
||||
free(hostips);
|
||||
|
||||
// secure the server
|
||||
//
|
||||
@@ -336,13 +338,12 @@ int main(int argc, char *argv[]) {
|
||||
sigaddset(&block, SIGHUP);
|
||||
sigaddset(&block, SIGQUIT);
|
||||
pthread_attr_t attr;
|
||||
int pagesz = getauxval(AT_PAGESZ);
|
||||
unassert(!pthread_attr_init(&attr));
|
||||
unassert(!pthread_attr_setstacksize(&attr, 65536));
|
||||
unassert(!pthread_attr_setguardsize(&attr, pagesz));
|
||||
unassert(!pthread_attr_setguardsize(&attr, getpagesize()));
|
||||
unassert(!pthread_attr_setsigmask_np(&attr, &block));
|
||||
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0));
|
||||
pthread_t *th = gc(calloc(threads, sizeof(pthread_t)));
|
||||
pthread_t *th = calloc(threads, sizeof(pthread_t));
|
||||
for (i = 0; i < threads; ++i) {
|
||||
int rc;
|
||||
++a_workers;
|
||||
@@ -399,6 +400,7 @@ int main(int argc, char *argv[]) {
|
||||
for (i = 0; i < threads; ++i) {
|
||||
unassert(!pthread_join(th[i], 0));
|
||||
}
|
||||
free(th);
|
||||
|
||||
// close the server socket
|
||||
if (!IsWindows())
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "ctl/ostream.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
ctl::cout << "hello world\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -60,6 +60,7 @@ Contact: [email protected]");
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/ctype.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/alg.h"
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/safemacros.h"
|
||||
#include "libc/inttypes.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/ctype.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
+14
-5
@@ -119,10 +119,11 @@
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/tms.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/ctype.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
@@ -11142,7 +11143,9 @@ static void exitreset() {
|
||||
inps4 = 0;
|
||||
}
|
||||
/* from expand.c: */
|
||||
{ ifsfree(); }
|
||||
{
|
||||
ifsfree();
|
||||
}
|
||||
/* from redir.c: */
|
||||
{
|
||||
/*
|
||||
@@ -11165,9 +11168,13 @@ static void forkreset() {
|
||||
}
|
||||
}
|
||||
/* from main.c: */
|
||||
{ handler = &main_handler; }
|
||||
{
|
||||
handler = &main_handler;
|
||||
}
|
||||
/* from redir.c: */
|
||||
{ redirlist = NULL; }
|
||||
{
|
||||
redirlist = NULL;
|
||||
}
|
||||
/* from trap.c: */
|
||||
{
|
||||
char **tp;
|
||||
@@ -11198,7 +11205,9 @@ static void reset() {
|
||||
popallfiles();
|
||||
}
|
||||
/* from var.c: */
|
||||
{ unwindlocalvars(0); }
|
||||
{
|
||||
unwindlocalvars(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void calcsize(union node *n) {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/ctype.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/intrin/describebacktrace.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
#include "libc/calls/cachestat.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
|
||||
int sys_cachestat(int, struct cachestat_range *, struct cachestat *, uint32_t);
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/wintime.internal.h"
|
||||
#include "libc/intrin/getauxval.internal.h"
|
||||
#include "libc/intrin/getauxval.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/describeflags.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time.h"
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/describeflags.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
|
||||
#ifdef __aarch64__
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/describeflags.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/timeval.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/describeflags.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/intrin/fds.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
|
||||
+2
-2
@@ -20,14 +20,14 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/intrin/fds.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/describeflags.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/strace.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
||||
Loaded 100 of 985 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user