Compare commits

...
76 Commits
Author SHA1 Message Date
Justine Tunney 617ddfee93 Release Cosmopolitan v3.5.2 2024-06-29 10:58:47 -07:00
Justine Tunney 464858dbb4 Fix bugs with new memory manager
This fixes a regression in mmap(MAP_FIXED) on Windows caused by a recent
revision. This change also fixes ZipOS so it no longer needs a MAP_FIXED
mapping to open files from the PKZIP store. The memory mapping mutex was
implemented incorrectly earlier which meant that ftrace and strace could
cause cause crashes. This lock and other recursive mutexes are rewritten
so that it should be provable that recursive mutexes in cosmopolitan are
asynchronous signal safe.
2024-06-29 10:53:57 -07:00
Justine Tunney 6de12c1032 Upgrade to superconfigure z0.0.44 2024-06-29 05:07:25 -07:00
Justine Tunney a16eb76f5e Fix build break 2024-06-29 04:34:27 -07:00
Justine Tunney 021c53ba32 Add more CTL content 2024-06-28 19:09:54 -07:00
Justine Tunney 38921dc46b Introduce more CTL content
This change introduces accumulate, addressof, advance, all_of, distance,
array, enable_if, allocator_traits, back_inserter, bad_alloc, is_signed,
any_of, copy, exception, fill, fill_n, is_same, is_same_v, out_of_range,
lexicographical_compare, is_integral, uninitialized_fill_n, is_unsigned,
numeric_limits, uninitialized_fill, iterator_traits, move_backward, min,
max, iterator_tag, move_iterator, reverse_iterator, uninitialized_move_n

This change experiments with rewriting the ctl::vector class to make the
CTL design more similar to the STL. So far it has not slowed things down
to have 42 #include lines rather than 2, since it's still almost nothing
compared to LLVM's code. In fact the closer we can flirt with being just
like libcxx, the better chance we might have of discovering exactly what
makes it so slow to compile. It would be an enormous discovery if we can
find one simple trick to solving the issue there instead.

This also fixes a bug in `ctl::string(const string &s)` when `s` is big.
2024-06-27 22:42:32 -07:00
Steven Dee (Jōshin) 054da021d0 ctl::string benchmarking code (#1200) 2024-06-26 21:30:05 -04:00
Justine Tunney 199662071a Make std::random_device use getentropy() 2024-06-24 07:32:07 -07:00
Justine Tunney 572ac7d100 Release Cosmopolitan v3.5.1 2024-06-24 06:54:15 -07:00
Justine Tunney d461c6f47d Do more quality assurance work 2024-06-24 06:53:49 -07:00
Justine Tunney 67b19ae733 Release Cosmopolitan v3.5.0 2024-06-23 22:45:14 -07:00
Justine Tunney c4c812c154 Introduce ctl::set and ctl::map
We now have a C++ red-black tree implementation that implements standard
template library compatible APIs while compiling 10x faster than libcxx.
It's not as beautiful as the red-black tree implementation in Plinko but
this will get the job done and the test proves it upholds all invariants

This change also restores CheckForMemoryLeaks() support and fixes a real
actual bug I discovered with Doug Lea's dlmalloc_inspect_all() function.
2024-06-23 22:27:11 -07:00
Justine Tunney 388e236360 Revert misguided dlmalloc optimization 2024-06-22 09:55:02 -07:00
Justine Tunney f2c8ddbbe3 Fix --strace use-after-free in pthread_join() 2024-06-22 06:05:52 -07:00
Justine Tunney d1d4388201 Delete ASAN
It hasn't been helpful enough to be justify the maintenance burden. What
actually does help is mprotect(), kprintf(), --ftrace and --strace which
can always be counted upon to work correctly. We aren't losing much with
this change. Support for ASAN on AARCH64 was never implemented. Applying
ASAN to the core libc runtimes was disabled many months ago. If there is
some way to have an ASAN runtime for user programs that is less invasive
we can potentially consider reintroducing support. But now is premature.
2024-06-22 05:45:49 -07:00
Justine Tunney 6ffed14b9c Rewrite memory manager
Actually Portable Executable now supports Android. Cosmo's old mmap code
required a 47 bit address space. The new implementation is very agnostic
and supports both smaller address spaces (e.g. embedded) and even modern
56-bit PML5T paging for x86 which finally came true on Zen4 Threadripper

Cosmopolitan no longer requires UNIX systems to observe the Windows 64kb
granularity; i.e. sysconf(_SC_PAGE_SIZE) will now report the host native
page size. This fixes a longstanding POSIX conformance issue, concerning
file mappings that overlap the end of file. Other aspects of conformance
have been improved too, such as the subtleties of address assignment and
and the various subtleties surrounding MAP_FIXED and MAP_FIXED_NOREPLACE

On Windows, mappings larger than 100 megabytes won't be broken down into
thousands of independent 64kb mappings. Support for MAP_STACK is removed
by this change; please use NewCosmoStack() instead.

Stack overflow avoidance is now being implemented using the POSIX thread
APIs. Please use GetStackBottom() and GetStackAddr(), instead of the old
error-prone GetStackAddr() and HaveStackMemory() APIs which are removed.
2024-06-22 05:45:11 -07:00
Justine Tunney 7f6d0b8709 Support -x LANG flag in cosmocc 2024-06-20 23:55:46 -07:00
Steven Dee (Jōshin) d7b1919b29 ctl::unique_ptr improvements and cleanup (#1221)
Explicitly value-initializes the deleter, even though I have not found a
way to get the deleter to act like it’s been default-initialized in unit
tests so far.

Uses auto in reset. The static cast is apparently not needed (unless I’m
missing some case I didn’t think of.)

Implements the general move constructor - turns out that the reason this
didn’t work before was that default_delete<U> was not move constructible
from default_delete<T>.

Drop inline specifiers from functions defined entirely inside the struct
definition since they are implicitly inline.

* Cleans up reset to match spec

Remove the variants from the T[] specialization. Also follow the spec on
the order of operations in reset, which may matter if we are deleting an
object that has a reference to the unique_ptr that is being reset. (?)

* Tests Base/Derived reset.

* Adds some constexpr declarations.

* Adds default_delete specialization for T[].

* Makes parameters const.
2024-06-20 18:44:31 -04:00
Steven Dee (Jōshin) f86e6f8eb0 Make new.cc definitions weak (#1233)
The STL says that these should be replaceable by user code.

new.cc now defines only a few direct functions (including a free wrapper
that perplexingly is needed since g++ didn’t want to alias "free".) Now,
all of the operators are weak references to those functions.
2024-06-20 15:20:54 -04:00
Steven Dee (Jōshin) 7e780e57d4 More ctl::string optimization (#1232)
Moves some isbig checks into string.h, enabling smarter optimizations to
be made on small strings. Also we no longer zero out our string prior to
calling the various constructors, buying back the performance we lost on
big strings when we made the small-string optimization. We further add a
little optimization to the big_string copy constructor: if the string is
using half or more of its capacity, then we don’t recompute capacity and
just take the old string’s. As well, the copy constructor always makes a
small string when it will fit, even if copied from a big string that got
truncated.

This also reworks the test to follow the idiom adopted elsewhere re stl,
and adds a helper function to tell if a string is small based on data().
2024-06-20 14:52:12 -04:00
Steven Dee (Jōshin) 9a5a13854d CTL: utility.h, use ctl::swap in string (#1227)
* Add ctl utility.h

Implements forward, move, swap, and declval. This commit also adds a def
for nullptr_t to cxx.inc. We need it now because the CTL headers stopped
including anything from libc++, so we no longer get their basic types.

* Use ctl::swap in string

The STL spec says that swap is located in the string_view header anyawy.
Performance-wise this is a noop, but it’s slightly cleaner.
2024-06-19 01:00:59 -04:00
Steven Dee (Jōshin) a795017416 Fix c.inc _Atomic define for C++ (#1231)
c.inc (AFAICT erroneously) defined _Atomic(t) as `volatile t *`, when it
should have just said `volatile t`, when __STDC_VERSION__ was too small.
This happens when we’re compiling C++, but in C++11, _Atomic is a define
supplied by the STL rather than a keyword supplied by the compiler. Wait
though, it gets better: in C++11, _Atomic hooks you into the morass that
is stdatomic.h, and ultimately refers everything back to std::atomic<T>.

The gory, horrifying details are in libcxx's __atomic/cxx_atomic_impl.h.
The tldr is that for our purposes it’s fine to just say volatile and use
the normal libc/intrin/atomic.h functions.
2024-06-17 21:12:02 -07:00
Brian 8e3b361aeb Remove testing label from labeler.yml (#1220)
#1219 had an issue with noisy testing label. Investigated if there is a
syntax to make it more exclusive, but turns out there isn't one yet. So
let's remove an manually add it in as needed.

Fixes #1219.
2024-06-16 11:45:57 -04:00
Steven Dee (Jōshin) f9dd5683a4 Implement ctl::unique_ptr (#1216)
The way unique_ptr is supposed to work is as a purely compile-time check
that your raw pointers are getting deleted when they go out of scope. It
should ideally emit the same exact machine code as if you were using raw
pointers with manual deletes.

Part of what this means is that under normal circumstances, a unique_ptr
shouldn’t take up more space than a raw pointer - in other words, sizeof
unique_ptr<T> should == sizeof(T*).

The present PR doesn’t bother with the specialization for array types. I
also left a couple other parts of the STL API unimplemented. I’d love to
see someone else implement these, or I’ll get to them at some point.
2024-06-15 22:54:52 -04:00
Steven Dee (Jōshin) e38a6e7996 ctl string const/value tweaks (#1218)
The mangled name of a C++ function will typically not vary by const-ness
of a by-value parameter; in other words, there is no meaning to a const-
qualified by-value parameter in a function prototype. However, the const
keyword _does_ matter at function _definition_ time, like it does with a
variable declared in the body. So for prototypes, we strip out const for
by-value parameters; but for definitions, we leave them alone.

At function definition (as opposed to prototype), we add const to values
in parameters by default, unless we’re going to mutate them.

This commit also changes a couple of const string_view& to be simply by-
value string_view. A string_view is only two words; it rarely ever makes
sense to pass one by reference if it’s not going to be mutated.
2024-06-15 18:09:30 -07:00
Steven Dee (Jōshin) ddfaf3fee0 Explain the clang-format off in new.h 2024-06-15 17:17:04 -07:00
Michael Lenaghan 0dbf01bf1d Bring Lua to 5.4.6. (#1214)
This essentially re-does the work of #875 on top of master.

This is what I did to check that Cosmo's Lua extensions still worked:

```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```

`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):

```
stack traceback:
 [string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
 [string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.

This is what I did to check that Lua itself still worked:

```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```

There's one test failure, in `files.lua`:

```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```

That isn't a result of these changes; the same test is failing in
master.

The failure is here:

```lua
if not _port then   -- invalid seek
  local status, msg, code = io.stdin:seek("set", 1000)
  assert(not status and type(msg) == "string" and type(code) == "number")
end
```

The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.

If I comment out that one test, the remaining tests succeed.
2024-06-15 20:13:08 -04:00
Jōshin 3a599bfbe1 Update .git-blame-ignore-revs 2024-06-15 13:36:07 -07:00
Jōshin 89fc95fefd Rerun clang-format on the repo (#1217)
🚨 clang-format changes output per version!

This is with version 19.0.0. The modifications seem to be fixing the old
version’s errors - mainly involving omitted whitespace around binary ops
and inserted whitespace between goto labels and colons (if followed by a
curly brace.)

Also fixes a few mistakes made by e.g. someone (ahem) forgetting to pass
his ctl/string.h modifications through it.

We should add this to .git-blame-ignore-revs once we have its final hash
on master.
2024-06-15 16:34:48 -04:00
Jōshin 8e37ee2598 ctl::string cleanup (#1215)
We now fully initialize a ctl::string’s memory, so that it is always set
to a well-defined value, thus making it always safe to memcpy out of it.
This incidentally makes our string::swap function legal, which it wasn’t
before. This also saves us a store in string::reserve.

Now that we have made both big_string and small_string POD, I believe it
is safe to elide the launder calls, and have done so, thus cleaning up a
lot of the blob-related code.

I also got rid of set_big_capacity and replaced it with a set_big_string
that leaves us in a well-defined state afterwards. This function also is
able to be somewhat simpler; rather than delicate bit-twiddling, it just
reaches straight into blob and rewrites it wholesale.

Overall, this shaves about 1–2ns off of most benchmarks, and adds 1ns to
only one of them - creating a string from a char *.
2024-06-15 10:49:52 -07:00
Jōshin d9b4f647d8 Uncomment swap test (#1210) 2024-06-10 21:51:19 -07:00
Jōshin 0dde3a0e70 Get rid of preprocessor stuff in test (#1202)
Also it's a bit more idiomatic to say s.npos rather than string::npos.
2024-06-10 07:00:37 -07:00
Jōshin 32643e9fa7 Decouple swap from std (#1211)
This allows you to implement your own swap function without it having to
be part of the std namespace. std::swap is still used if it's available.
2024-06-10 03:40:17 -07:00
Jōshin 0a92c78035 Remove erroneous ctl:: prefixes 2024-06-08 15:07:39 -07:00
Jōshin 118db71121 Provide a minimal new.h for CTL (#1205)
This replaces the STL <new> header. Mainly, it defines a global operator
new and operator delete, as well as the placement versions of these. The
placement versions are required to not get compile errors when trying to
write a placement new statement.

Each of these operators is defined with many, many different variants. A
glance at new.cc is recommended followed by a chaser of the Alexandrescu
talk "std::allocator is to Allocation as std::vector is to Vexation". We
must provide a global-namespace source-level definition of each operator
and it is illegal for any of them to be marked inline, so here we are.

The upshot is that we no longer need to include <new>, and our optional/
vector headers are self-contained.
2024-06-08 15:05:38 -07:00
Alkis Evlogimenos a0410f0170 Make big_string pod (#1204)
`big_string` is not pod which means it needs to be properly constructed
and destroyed. Instead make it POD and destroy it manually in `string`
destructor.
2024-06-08 10:02:33 -07:00
Alkis Evlogimenos d44a7dc603 Fix bugs in in ctl::optional (#1203)
Manually manage the lifetime of `value_` by using an anonymous
`union`. This fixes a bunch of double-frees and double-constructs.

Additionally move the `present_` flag last. When `T` has padding
`present_` will be placed there saving `alignof(T)` bytes from
`sizeof(optional<T>)`.
2024-06-07 20:47:24 -04:00
Jōshin 2ba6b0158f Fix some memory issues with ctl::string (#1201)
There were a few errors in how capacity and memory was being handled for
small strings. The capacity errors meant that small strings would become
big strings too soon, and the memory error introduced undefined behavior
that was caught by CheckMemoryLeaks in our test file but only sometimes.

The crucial change is in reserve: we only copy n bytes into p2, and then
we manually set the null terminator instead of expecting it to have been
there already. (E.g. it might not be there for an empty small string.)

We also fix one other doozy in append when we were exactly at the small-
to-big string boundary: we set the last byte (i.e., the remainder field)
to 0, then decremented it, giving us size_t max. Whoops. We boneheadedly
fix this by setting the 0 byte after we've fixed up the remainder, so it
is at worst a no-op.

Otherwise, capacity now works the same for small strings as it does with
big strings: it's the amount of space available including the null byte.

We test all of this with a new test that only gets included if our class
under test is not std::string (presumably meaning it's ctl::string.) The
test manually verifies that the small string optimization behaves how we
expect.

Since this test checks against std::string, we go ahead and include that
other header from the STL.

Also modifies the new test we introduced to also run on std::string, but
it just does the append without expecting anything about how its data is
stored. We also check that the string has the right value afterwards.
2024-06-07 01:15:37 -04:00
Jōshin f3effcb703 One more SSO erratum from #1199
Making a string_view from a string appears to take about 1.3ns no matter
what. 100% definitely no point deviating from the STL API over that.
2024-06-06 18:01:26 -07:00
Jōshin 03b476f943 Minor small-string errata from #1199
These commits were sitting on a local branch that I neglected to push
before merging. :(

* Use memcpy for string::reserve

* Remove fence comments
2024-06-06 17:56:30 -07:00
Jōshin 8b3e368e9a ctl::string small-string optimization (#1199)
A small-string optimization is a way of reusing inline storage space for
sufficiently small strings, rather than allocating them on the heap. The
current approach takes after an old Facebook string class: it reuses the
highest-order byte for flags and small-string size, in such a way that a
maximally-sized small string will have its last byte zeroed, making it a
null terminator for the C string.

The only flag we have is in the highest-order bit, that says whether the
string is big (set) or small (cleared.) Most of the logic switches based
on the value of this bit; e.g. data() returns big()->p if it's set, else
small()->buf if it's cleared. For a small string, the capacity is always
fixed at sizeof(string) - 1 bytes; we store the length in the last byte,
but we store it as the number of remaining bytes of capacity, so that at
max size, the last byte will read zero and serve as our null terminator.

Morally speaking, our class's storage is a union over two POD C structs.
For now I gravitated towards a slightly more obtuse approach: the string
class itself contains a blob of the right size, and we alias that blob's
pointer for the two structs, taking some care not to run afoul of object
lifetime rules in C++. If anyone wants to improve on this, contributions
are welcome.

This commit also introduces the `ctl::__` namespace. It can't be legally
spelled by library users, and serves as our version of boost's "detail".

We introduced a string::swap function, and we now use that in operator=.
operator= now takes its argument by value, so we never need to check for
the case where the pointers are equal and can just swap the entire store
of the argument with our own, leaving the C++ destructor to free our old
storage afterwards.

There are probably still a few places where our capacity is slightly off
and we grow too fast, although there don't appear to be any where we are
too slow. I will leave these to be fixed in future changes.
2024-06-06 20:50:51 -04:00
Brian df6b384e31 github: add labeler action (#1196)
Bit easier to do this as everything seems to be sorted into logical
folders. You may need to add new labels to support this however.
2024-06-06 05:51:36 -07:00
Brian 280bdec817 github: add issue template (#1195)
copy paste and adapted from llamafile but added a research template as
well for the more technical research tickets
2024-06-06 05:51:06 -07:00
Jōshin 2c5e7ec547 Add terminating :vi on some modelines
Noticed because the settings they specified weren't getting picked up by
editor sessions in those files.
2024-06-05 20:36:55 -07:00
Jōshin fdcb8b2f7e add formatting commit 2024-06-05 16:36:34 -07:00
Jōshin 04c6bc478e vim C++ filetype is still spelled "cpp" 2024-06-05 16:34:47 -07:00
Justine Tunney cc2c1893c5 Fix some nits 2024-06-05 04:05:49 -07:00
Justine Tunney 3093f0e467 Release Cosmopolitan v3.4.0 2024-06-05 03:07:03 -07:00
Justine Tunney 3609f65de3 Make malloc() go 200x faster
If pthread_create() is linked into the binary, then the cosmo runtime
will create an independent dlmalloc arena for each core. Whenever the
malloc() function is used it will index `g_heaps[sched_getcpu() / 2]`
to find the arena with the greatest hyperthread / numa locality. This
may be configured via an environment variable. For example if you say
`export COSMOPOLITAN_HEAP_COUNT=1` then you can restore the old ways.
Your process may be configured to have anywhere between 1 - 128 heaps

We need this revision because it makes multithreaded C++ applications
faster. For example, an HTTP server I'm working on that makes extreme
use of the STL went from 16k to 2000k requests per second, after this
change was made. To understand why, try out the malloc_test benchmark
which calls malloc() + realloc() in a loop across many threads, which
sees a a 250x improvement in process clock time and 200x on wall time

The tradeoff is this adds ~25ns of latency to individual malloc calls
compared to MODE=tiny, once the cosmo runtime has transitioned into a
fully multi-threaded state. If you don't need malloc() to be scalable
then cosmo provides many options for you. For starters the heap count
variable above can be set to put the process back in single heap mode
plus you can go even faster still, if you include tinymalloc.inc like
many of the programs in tool/build/.. are already doing since that'll
shave tens of kb off your binary footprint too. Theres also MODE=tiny
which is configured to use just 1 plain old dlmalloc arena by default

Another tradeoff is we need more memory now (except in MODE=tiny), to
track the provenance of memory allocation. This is so allocations can
be freely shared across threads, and because OSes can reschedule code
to different CPUs at any time.
2024-06-05 02:02:14 -07:00
Justine Tunney 9906f299bb Refactor and improve CTL and other code 2024-06-04 05:45:48 -07:00
Justine Tunney 1d8f37a2f0 Fix the MODE=tiny builds 2024-06-03 10:36:38 -07:00
Justine Tunney e677460d14 Delete .vscode folder
It hasn't been maintained in years. I'm tired of the root level of our
project having an advertisement for Microsoft Visual Studio Code. Your
preferred editor should be Emacs or Vim.
2024-06-03 09:40:45 -07:00
Justine Tunney 4937843f70 Introduce Cosmopolitan Templates Library (CTL) 2024-06-03 09:21:59 -07:00
Justine Tunney b003888696 Make __demangle() heap 10% more compact 2024-06-02 16:18:55 -07:00
Justine Tunney 2ca491dc56 Write more __demangle() tests 2024-06-02 07:37:15 -07:00
Justine Tunney 9aa353d88b Document __demangle() and fix a const func ptr bug 2024-06-02 04:15:48 -07:00
Justine Tunney c67faf61df Delete some unintentional code 2024-06-01 20:36:58 -07:00
Justine Tunney 165c6b37e2 Add C++ demangling to privileged runtime
Cosmo will now print C++ symbols correctly in --ftrace logs and
backtraces. Doing this required reducing the memory requirement
of the __demangle() function by 3x. This was accomplished using
16-bit indices and 16-bit malloc granularity. That puts a limit
on the longest symbol we can successfully decode, which I think
would be around 6553 characters long, given a 65536-byte buffer
2024-06-01 20:10:58 -07:00
Jōshin dcd626edf8 Add .git-blame-ignore-revs
If you follow the directions in that file then git blame will ignore the
listed commits. A commit should only go in that file if its only changes
were to formatting, particularly on a large part of the codebase (like a
change to .clang-format getting applied to the repo.)

Cribbed from here:

https://www.stefanjudis.com/today-i-learned/how-to-exclude-commits-from-git-blame/
2024-06-01 20:10:48 -07:00
Jōshin f032b5570b Run clang-format (#1197) 2024-06-01 16:30:43 -04:00
Justine Tunney ea081b262c Add some noexcept annotations 2024-06-01 03:19:53 -07:00
Justine Tunney fae1c32267 Encode ±INFINITY as ±1e5000
The V8 behavior of encoding infinity as null doesn't make sense to me.
Using ±1e5000 is better, because JSON.parse decodes it as INFINITY and
the information is preserved. This could be a breaking change for some
2024-06-01 03:19:50 -07:00
Justine Tunney 9b6718ac99 Improve backtraces
We're now able to rewind the instruction pointer in x86 backtraces. This
helps ensure addr2line cannot print information about unrelated adjacent
code. I've restored -fno-schedule-insns2 in most cases because it really
does cause unpredictable breakage for backtraces.
2024-05-30 15:23:11 -07:00
Justine Tunney cd672e251f Improve crash signal reporting on Windows
This change fixes a bug where exiting a crash signal handler on Windows
after adding the signal to uc_sigmask, but not correcting the CPU state
would cause the signal handler to loop infinitely, causing process hang

Another issue is that very tiny programs, that don't link posix signals
would not have their SIGILL / SIGSEGV / etc. status reported to Cosmo's
bash shell when terminating on crash. That's fixed by a tiny handler in
WinMain() that knows how to map WIN32 crash codes to the POSIX flavors.
2024-05-30 14:04:10 -07:00
Justine Tunney 500a47bc2f Fix undefined behavior in unit test
Fixes #1194
2024-05-29 20:31:46 -07:00
Justine Tunney e4d25d68e4 Drop support for Windows 8
Microsoft caused some very gentle breakages for Cosmopolitan. They
removed the version information from the PEB which caused uname to
report WINDOWS 0.0.0. We should have called GetVersionExW but that
doesn't really exist anymore either. Windows policy is now to give
whatever version we used in ape/ape.S. Windows8 has been EOL since
2023-01-10 so lets avoid our modern executables being relegated to
legacy infrastructure. Requiring Windows 10+ going forward lets us
remove runtime compatibility bloat from the codebase. Further note
Cosmopolitan maintains a Windows Vista branch on GitHub, so anyone
preferring the older versions, can still have a future with Cosmo.

Another neat thing this fixes is UTF-8 support in the console. The
changes Microsoft made broke the if statement that enabled UTF8 in
terminals. This explains why bug reports had broken arrows. In the
future this should be less of an issue, since the PEB code is gone
which means we more strictly conform to only Microsoft's WIN32 API
2024-05-29 19:37:47 -07:00
Justine Tunney f31a98d50a Fix bug with realpath() on Windows 2024-05-29 18:47:01 -07:00
Justine Tunney 2816df59b2 Increase tinymalloc granularity 2024-05-29 18:26:01 -07:00
Justine Tunney a05ce3ad9d Support avx512f + vpclmulqdq crc32() acceleration
Cosmo's _Cz_crc32() function now goes 73 GiB/s on Threadripper. This
will significantly improve the performance of the PKZIP file format.
This algorithm is also used by apelink, to create deterministic ids.
2024-05-29 10:13:37 -07:00
Justine Tunney 7c8df05042 Improve -march=native micro-architecture detection 2024-05-29 10:12:49 -07:00
Justine Tunney 4c77acdfcf Add LoadZipArgs() to <cosmo.h> 2024-05-29 10:12:20 -07:00
Justine Tunney b74b974cfd Introduce #include <tinygetopt.h>
The normal getopt() function is bloated because it links printf(). This
change exports the original authentic bsd getopt function, that cosmo's
always used internally so cosmocc users don't need to include internals
2024-05-29 10:11:17 -07:00
Justine Tunney 07cef612c3 Make dlmalloc 2.4x faster for multithreading
This change adds a TLS freelist for small dynamic memory allocations.
Cosmopolitan's TIB is now 512 bytes in size. Single-threaded malloc()
performance isn't impacted by this, until pthread_create() is called.
Single-threaded programs may also want to consider using:

    #include "libc/mem/tinymalloc.inc"

Which will shave 30k off the executable size and sometimes go faster.
2024-05-28 11:18:34 -07:00
Justine Tunney deaef81463 Favor siginfo_t over struct siginfo 2024-05-28 02:34:17 -07:00
Justine Tunney c638eabfe0 Fix compiler warning 2024-05-27 02:23:24 -07:00
Justine Tunney 8e68384e15 Upgrade to 2022-era LLVM LIBCXX 2024-05-27 02:12:27 -07:00
2930 changed files with 190265 additions and 79506 deletions

No files matched your search

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