Compare commits

...
17 Commits
Author SHA1 Message Date
Justine Tunney 70f77aad33 Release Cosmopolitan v3.5.4 2024-07-01 07:17:57 -07:00
Justine Tunney d0cd719375 Make more CTL fixes 2024-07-01 07:17:57 -07:00
Justine Tunney 61370983e1 Complete the Windows TLS fix made in e437bed00 2024-07-01 07:17:57 -07:00
Terror 72511ff0ac [Redbean] Add UuidV7 method (#1213)
To Complete #1140 add UUID version 7 to Redbean
2024-07-01 06:06:56 -07:00
Justine Tunney c1f8d0678c Mark ctl::to_string() noexcept 2024-07-01 05:54:59 -07:00
Justine Tunney e627bfa359 Introduce ctl::to_string() 2024-07-01 05:40:38 -07:00
Justine Tunney acbabedf27 Make CTL definitions less ambiguous 2024-07-01 03:48:28 -07:00
Justine Tunney 239f8ce76e Release Cosmopolitan v3.5.3 2024-07-01 02:07:56 -07:00
Justine Tunney ca4cf67eb8 Include more programs in cosmocc
The Cosmopolitan Compiler Collection now includes the following programs

- `ar.ape` is a faster alternative to `ar rcsD` for creating determistic
  static archives. It's ~10x faster than GNU because it isn't quadratic.
  It'll even outperform LLVM ar by 2x, thanks to writev/copy_file_range.

- `sha256sum.ape` is a faster alternative to the `sha256sum` command. It
  goes 2x faster since it leverages vectorized assembly implementations.

- `resymbol` is a brand new program we invented, like objcopy, that lets
  you rename all the global symbols in a .o file to have a new suffix or
  prefix. In the future, this will be used by cosmocc automatically when
  building -O3 math kernels, that need to be vectorized for all hardware

- `gzip.ape` is a faster version of the `gzip` command, that is included
  by most Linux distros. It gains better performance using Chromium Zlib
  which, once again, includes highly optimized assembly, that Mark Adler
  won't merge into the official MS-DOS compatible zlib codebase.

- `cocmd` is the cosmopolitan shell. It can function as a faster `sh -c`
  alternative than bash and dash as the `SHELL = /opt/cosmocc/bin/cocmd`
  at the top of your Makefile. Please note you should be using the cosmo
  fork of GNU make (already included), since normal make won't recognize
  this as a bourne-compatible shell and remove the execve() optimization
  which makes things slower. In some ways that's true. This doesn't have
  a complete POSIX shell implementation. However it's enough for cosmo's
  mono repo. It also implements faster behaviors in some respects.

The following programs are also introduced, which aren't as interesting.
The main reason why they're here is so Cosmopolitan's mono repo shall be
able to remove build/bootstrap/ in future editions. That way we can keep
build utilities better up to date, without bloating the git history much

- `chmod.ape` for hermeticity
- `cp.ape` for hermeticity
- `echo.ape` for hermeticity
- `objbincopy` is an objcopy-like tool that's used to build ape loader
- `package.ape` is used for strict dependency checking of object graph
- `rm.ape` for hermeticity
- `touch.ape` for hermeticity
2024-07-01 02:05:25 -07:00
Justine Tunney 78d3b86ec7 Fix Android support
Thanks to @aj47 (techfren.net) the new Cosmo memory manager is confirmed
to be working on Android!! The only issue turned out to be forgetting to
update the program address in the linker script. We now know w/ absolute
certainty that APE binaries as complex as llamafile, now work correctly.
2024-07-01 01:06:47 -07:00
Justine Tunney 44191b3f50 Add more type traits to CTL 2024-06-30 20:59:38 -07:00
Justine Tunney e437bed006 Fix crash caused when Windows needs a lot of TLS 2024-06-30 20:53:43 -07:00
Justine Tunney 76957983cf Make POSIX threads improvements
- Ensure SIGTHR isn't blocked in newly created threads
- Use TIB rather than thread_local for thread atexits
- Make POSIX thread keys atomic within thread
- Don't bother logging prctl() to --strace
- Log thread destructor names to --strace
2024-06-30 15:38:59 -07:00
Justine Tunney 387310c659 Fix issue with ctl::vector constructor 2024-06-30 02:26:38 -07:00
Justine Tunney 4cb5e21ba8 Introduce pthread_decimate_np() api
This is useful with CheckForMemoryLeaks().
2024-06-30 02:26:06 -07:00
Justine Tunney 1bf2d8e308 Further improve mmap() locking story
The way to use double linked lists, is to remove all the things you want
to work on, insert them into a new list on the stack. Then once you have
all the work items, you release the lock, do your work, and then lock it
again, to add the shelled out items back to a global freelist.
2024-06-29 17:12:43 -07:00
Justine Tunney 98e684622b Add iostream to CTL 2024-06-29 15:45:09 -07:00
86 changed files with 2861 additions and 531 deletions

No files matched your search

+2 -2
View File
@@ -256,7 +256,6 @@ include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
include libc/proc/BUILD.mk # │ You can now use threads
include libc/dlopen/BUILD.mk # │ You can now use processes
include libc/thread/BUILD.mk # │ You can finally call malloc()
include ctl/BUILD.mk # │
include third_party/zlib/BUILD.mk # │
include libc/stdio/BUILD.mk # │
include tool/hello/BUILD.mk # │
@@ -285,9 +284,10 @@ include third_party/ncurses/BUILD.mk # │
include third_party/readline/BUILD.mk # │
include third_party/libunwind/BUILD.mk # |
include third_party/libcxxabi/BUILD.mk # |
include third_party/double-conversion/BUILD.mk # │
include ctl/BUILD.mk # │
include third_party/libcxx/BUILD.mk # │
include third_party/openmp/BUILD.mk # │
include third_party/double-conversion/BUILD.mk # │
include third_party/pcre/BUILD.mk # │
include third_party/less/BUILD.mk # │
include net/https/BUILD.mk # │
+1 -1
View File
@@ -12,7 +12,7 @@ OUTPUT_FORMAT("elf64-littleaarch64",
SECTIONS {
. = SEGMENT_START("text-segment", 0x010000000000);
. = SEGMENT_START("text-segment", 0x000800000000);
__executable_start = .;
. += SIZEOF_HEADERS;
Binary file not shown.
+6
View File
@@ -18,7 +18,13 @@ CTL_A_CHECKS = \
CTL_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_STR \
THIRD_PARTY_DOUBLECONVERSION \
THIRD_PARTY_GDTOA \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
+20 -24
View File
@@ -11,59 +11,55 @@ struct allocator_traits
{
using allocator_type = Alloc;
using value_type = typename Alloc::value_type;
using pointer = typename Alloc::pointer;
using const_pointer = typename Alloc::const_pointer;
using pointer = typename Alloc::value_type*;
using const_pointer = const typename Alloc::value_type*;
using void_pointer = void*;
using const_void_pointer = const void*;
using difference_type = typename Alloc::difference_type;
using size_type = typename Alloc::size_type;
using difference_type = ptrdiff_t;
using size_type = size_t;
using propagate_on_container_copy_assignment = false_type;
using propagate_on_container_move_assignment = true_type;
using propagate_on_container_swap = false_type;
using is_always_equal = true_type;
using propagate_on_container_copy_assignment = ctl::false_type;
using propagate_on_container_move_assignment = ctl::true_type;
using propagate_on_container_swap = ctl::false_type;
using is_always_equal = ctl::true_type;
template<typename T>
using rebind_alloc = typename Alloc::template rebind<T>::other;
struct rebind_alloc
{
using other = typename Alloc::template rebind<T>::other;
};
template<typename T>
using rebind_traits = allocator_traits<rebind_alloc<T>>;
using rebind_traits = allocator_traits<typename rebind_alloc<T>::other>;
__attribute__((__always_inline__)) static pointer allocate(Alloc& a,
size_type n)
static pointer allocate(Alloc& a, size_type n)
{
return a.allocate(n);
}
__attribute__((__always_inline__)) static void deallocate(Alloc& a,
pointer p,
size_type n)
static void deallocate(Alloc& a, pointer p, size_type n)
{
a.deallocate(p, n);
}
template<typename T, typename... Args>
__attribute__((__always_inline__)) static void construct(Alloc& a,
T* p,
Args&&... args)
static void construct(Alloc& a, T* p, Args&&... args)
{
::new ((void*)p) T(static_cast<Args&&>(args)...);
}
template<typename T>
__attribute__((__always_inline__)) static void destroy(Alloc& a, T* p)
static void destroy(Alloc& a, T* p)
{
p->~T();
}
__attribute__((__always_inline__)) static size_type max_size(
const Alloc& a) noexcept
static size_type max_size(const Alloc& a) noexcept
{
return __PTRDIFF_MAX__ / sizeof(value_type);
return a.max_size();
}
__attribute__((__always_inline__)) static Alloc
select_on_container_copy_construction(const Alloc& a)
static Alloc select_on_container_copy_construction(const Alloc& a)
{
return a;
}
+6 -2
View File
@@ -37,24 +37,28 @@ struct array
constexpr reference at(size_type pos)
{
if (pos >= N)
throw ctl::out_of_range("out of range");
throw ctl::out_of_range();
return elems[pos];
}
constexpr const_reference at(size_type pos) const
{
if (pos >= N)
throw ctl::out_of_range("out of range");
throw ctl::out_of_range();
return elems[pos];
}
constexpr reference operator[](size_type pos)
{
if (pos >= N)
__builtin_trap();
return elems[pos];
}
constexpr const_reference operator[](size_type pos) const
{
if (pos >= N)
__builtin_trap();
return elems[pos];
}
+1 -1
View File
@@ -6,7 +6,7 @@
namespace ctl {
class bad_alloc : public exception
class bad_alloc : public ctl::exception
{
public:
bad_alloc() noexcept = default;
+8 -7
View File
@@ -16,15 +16,16 @@ template<typename T>
struct decay
{
private:
typedef typename remove_reference<T>::type U;
typedef typename ctl::remove_reference<T>::type U;
public:
typedef typename conditional<
is_array<U>::value,
typename remove_extent<U>::type*,
typename conditional<is_function<U>::value,
typename add_pointer<U>::type,
typename remove_cv<U>::type>::type>::type type;
typedef typename ctl::conditional<
ctl::is_array<U>::value,
typename ctl::remove_extent<U>::type*,
typename ctl::conditional<ctl::is_function<U>::value,
typename ctl::add_pointer<U>::type,
typename ctl::remove_cv<U>::type>::type>::type
type;
};
template<typename T>
+7 -5
View File
@@ -8,28 +8,30 @@
namespace ctl {
template<class InputIter>
constexpr typename iterator_traits<InputIter>::difference_type
constexpr typename ctl::iterator_traits<InputIter>::difference_type
distance_impl(InputIter first, InputIter last, input_iterator_tag)
{
typename iterator_traits<InputIter>::difference_type res(0);
typename ctl::iterator_traits<InputIter>::difference_type res(0);
for (; first != last; ++first)
++res;
return res;
}
template<class RandIter>
constexpr typename iterator_traits<RandIter>::difference_type
constexpr typename ctl::iterator_traits<RandIter>::difference_type
distance_impl(RandIter first, RandIter last, random_access_iterator_tag)
{
return last - first;
}
template<class InputIter>
constexpr typename iterator_traits<InputIter>::difference_type
constexpr typename ctl::iterator_traits<InputIter>::difference_type
distance(InputIter first, InputIter last)
{
return distance_impl(
first, last, typename iterator_traits<InputIter>::iterator_category());
first,
last,
typename ctl::iterator_traits<InputIter>::iterator_category());
}
} // namespace ctl
+35
View File
@@ -0,0 +1,35 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "dubble.h"
namespace ctl {
const double_conversion::DoubleToStringConverter kDoubleToPrintfG(
double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
double_conversion::DoubleToStringConverter::NO_TRAILING_ZERO,
"inf",
"nan",
'e',
-6,
10, // let 32-bit ints be represented without exponent
6,
0,
0);
} // namespace ctl
+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 COSMOPOLITAN_CTL_DUBBLE_H_
#define COSMOPOLITAN_CTL_DUBBLE_H_
#include "third_party/double-conversion/double-to-string.h"
namespace ctl {
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
} // namespace ctl
#endif // COSMOPOLITAN_CTL_DUBBLE_H_
+2
View File
@@ -11,10 +11,12 @@ struct integral_constant
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type;
constexpr operator value_type() const noexcept
{
return value;
}
constexpr value_type operator()() const noexcept
{
return value;
+39
View File
@@ -0,0 +1,39 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ios.h"
namespace ctl {
ios::ios(FILE* file) : file_(file)
{
}
ios::~ios() = default;
ios&
ios::operator=(ios&& other) noexcept
{
if (this != &other) {
file_ = other.file_;
other.file_ = nullptr;
}
return *this;
}
} // namespace ctl
+27
View File
@@ -0,0 +1,27 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IOS_H_
#define CTL_IOS_H_
#include "ios_base.h"
struct FILE;
namespace ctl {
class ios : public ios_base
{
public:
explicit ios(FILE*);
virtual ~ios();
protected:
ios& operator=(ios&&) noexcept;
FILE* file_;
private:
ios(const ios&) = delete;
};
} // namespace ctl
#endif // CTL_IOS_H_
+118
View File
@@ -0,0 +1,118 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ios_base.h"
namespace ctl {
ios_base::ios_base() : state_(goodbit), flags_(skipws | dec)
{
}
ios_base::~ios_base() = default;
ios_base::fmtflags
ios_base::flags() const
{
return static_cast<ios_base::fmtflags>(flags_);
}
ios_base::fmtflags
ios_base::flags(fmtflags fmtfl)
{
int old = flags_;
flags_ = fmtfl;
return static_cast<ios_base::fmtflags>(old);
}
ios_base::fmtflags
ios_base::setf(fmtflags fmtfl)
{
int old = flags_;
flags_ |= fmtfl;
return static_cast<ios_base::fmtflags>(old);
}
ios_base::fmtflags
ios_base::setf(fmtflags fmtfl, fmtflags mask)
{
int old = flags_;
flags_ = (flags_ & ~mask) | (fmtfl & mask);
return static_cast<ios_base::fmtflags>(old);
}
void
ios_base::unsetf(fmtflags mask)
{
flags_ &= ~mask;
}
ios_base::iostate
ios_base::rdstate() const
{
return static_cast<ios_base::iostate>(state_);
}
void
ios_base::clear(int state)
{
state_ = state;
}
void
ios_base::setstate(int state)
{
state_ |= state;
}
bool
ios_base::good() const
{
return state_ == goodbit;
}
bool
ios_base::eof() const
{
return (state_ & eofbit) != 0;
}
bool
ios_base::fail() const
{
return (state_ & (failbit | badbit)) != 0;
}
bool
ios_base::bad() const
{
return (state_ & badbit) != 0;
}
bool
ios_base::operator!() const
{
return fail();
}
ios_base::operator bool() const
{
return !fail();
}
} // namespace ctl
+86
View File
@@ -0,0 +1,86 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IOS_BASE_H_
#define CTL_IOS_BASE_H_
namespace ctl {
class ios_base
{
public:
typedef size_t streamsize;
enum iostate
{
goodbit = 0,
badbit = 1,
failbit = 2,
eofbit = 4
};
enum fmtflags
{
boolalpha = 1 << 0,
dec = 1 << 1,
fixed = 1 << 2,
hex = 1 << 3,
internal = 1 << 4,
left = 1 << 5,
oct = 1 << 6,
right = 1 << 7,
scientific = 1 << 8,
showbase = 1 << 9,
showpoint = 1 << 10,
showpos = 1 << 11,
skipws = 1 << 12,
unitbuf = 1 << 13,
uppercase = 1 << 14,
adjustfield = left | right | internal,
basefield = dec | oct | hex,
floatfield = scientific | fixed
};
enum openmode
{
app = 1 << 0,
binary = 1 << 1,
in = 1 << 2,
out = 1 << 3,
trunc = 1 << 4,
ate = 1 << 5
};
protected:
ios_base();
virtual ~ios_base();
int state_;
int flags_;
public:
fmtflags flags() const;
fmtflags flags(fmtflags);
fmtflags setf(fmtflags);
fmtflags setf(fmtflags, fmtflags);
void unsetf(fmtflags);
iostate rdstate() const;
void clear(int = goodbit);
void setstate(int);
bool good() const;
bool eof() const;
bool fail() const;
bool bad() const;
bool operator!() const;
explicit operator bool() const;
private:
ios_base(const ios_base&) = delete;
ios_base& operator=(const ios_base&) = delete;
};
} // namespace ctl
#endif // CTL_IOS_BASE_H_
+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_IS_ABSTRACT_H_
#define CTL_IS_ABSTRACT_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_abstract : public ctl::integral_constant<bool, __is_abstract(T)>
{};
template<typename T>
inline constexpr bool is_abstract_v = __is_abstract(T);
} // namespace ctl
#endif // CTL_IS_ABSTRACT_H_
+3 -3
View File
@@ -7,15 +7,15 @@
namespace ctl {
template<typename T>
struct is_array : false_type
struct is_array : ctl::false_type
{};
template<typename T, size_t N>
struct is_array<T[N]> : true_type
struct is_array<T[N]> : ctl::true_type
{};
template<typename T>
struct is_array<T[]> : true_type
struct is_array<T[]> : ctl::true_type
{};
template<typename T>
+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_IS_BASE_OF_H_
#define CTL_IS_BASE_OF_H_
#include "integral_constant.h"
namespace ctl {
template<typename Base, typename Derived>
struct is_base_of
: public ctl::integral_constant<bool, __is_base_of(Base, Derived)>
{};
template<typename Base, typename Derived>
inline constexpr bool is_base_of_v = __is_base_of(Base, Derived);
} // namespace ctl
#endif // CTL_IS_BASE_OF_H_
+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_IS_CLASS_H_
#define CTL_IS_CLASS_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_class : public ctl::integral_constant<bool, __is_class(T)>
{};
template<typename T>
inline constexpr bool is_class_v = __is_class(T);
} // namespace ctl
#endif // CTL_IS_CLASS_H_
+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_IS_CONSTRUCTIBLE_H_
#define CTL_IS_CONSTRUCTIBLE_H_
#include "integral_constant.h"
namespace ctl {
template<class _Tp, class... _Args>
struct is_constructible
: public ctl::integral_constant<bool, __is_constructible(_Tp, _Args...)>
{};
template<class _Tp, class... _Args>
inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
} // namespace ctl
#endif // CTL_IS_CONSTRUCTIBLE_H_
+4 -5
View File
@@ -2,7 +2,6 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_CONVERTIBLE_H_
#define CTL_IS_CONVERTIBLE_H_
#include "ctl/integral_constant.h"
#include "ctl/void_t.h"
@@ -16,7 +15,7 @@ declval() noexcept;
namespace detail {
template<typename From, typename To, typename = void>
struct is_convertible_impl : false_type
struct is_convertible_impl : ctl::false_type
{};
template<typename From, typename To>
@@ -28,15 +27,15 @@ struct is_convertible_impl<From,
// Handle void types separately
template<>
struct is_convertible_impl<void, void> : true_type
struct is_convertible_impl<void, void> : ctl::true_type
{};
template<typename To>
struct is_convertible_impl<void, To> : false_type
struct is_convertible_impl<void, To> : ctl::false_type
{};
template<typename From>
struct is_convertible_impl<From, void> : false_type
struct is_convertible_impl<From, void> : ctl::false_type
{};
} // namespace detail
+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_IS_EMPTY_H_
#define CTL_IS_EMPTY_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_empty : public ctl::integral_constant<bool, __is_empty(T)>
{};
template<typename T>
inline constexpr bool is_empty_v = __is_empty(T);
} // namespace ctl
#endif // CTL_IS_EMPTY_H_
+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_IS_ENUM_H_
#define CTL_IS_ENUM_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_enum : public ctl::integral_constant<bool, __is_enum(T)>
{};
template<typename T>
inline constexpr bool is_enum_v = __is_enum(T);
} // namespace ctl
#endif // CTL_IS_ENUM_H_
+25 -25
View File
@@ -8,111 +8,111 @@ namespace ctl {
// Primary template
template<class>
struct is_function : false_type
struct is_function : ctl::false_type
{};
// Specializations for various function types
// Regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : true_type
struct is_function<Ret(Args...)> : ctl::true_type
{};
// Functions with cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : true_type
struct is_function<Ret(Args...) const> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : true_type
struct is_function<Ret(Args...) volatile> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : true_type
struct is_function<Ret(Args...) const volatile> : ctl::true_type
{};
// Functions with ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...)&> : true_type
struct is_function<Ret(Args...)&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const&> : true_type
struct is_function<Ret(Args...) const&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile&> : true_type
struct is_function<Ret(Args...) volatile&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile&> : true_type
struct is_function<Ret(Args...) const volatile&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &&> : true_type
struct is_function<Ret(Args...) &&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const&&> : true_type
struct is_function<Ret(Args...) const&&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile&&> : true_type
struct is_function<Ret(Args...) volatile&&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile&&> : true_type
struct is_function<Ret(Args...) const volatile&&> : ctl::true_type
{};
// Variadic functions
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...)> : true_type
struct is_function<Ret(Args..., ...)> : ctl::true_type
{};
// Variadic functions with cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const> : true_type
struct is_function<Ret(Args..., ...) const> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) volatile> : true_type
struct is_function<Ret(Args..., ...) volatile> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const volatile> : true_type
struct is_function<Ret(Args..., ...) const volatile> : ctl::true_type
{};
// Variadic functions with ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...)&> : true_type
struct is_function<Ret(Args..., ...)&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const&> : true_type
struct is_function<Ret(Args..., ...) const&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) volatile&> : true_type
struct is_function<Ret(Args..., ...) volatile&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const volatile&> : true_type
struct is_function<Ret(Args..., ...) const volatile&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) &&> : true_type
struct is_function<Ret(Args..., ...) &&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const&&> : true_type
struct is_function<Ret(Args..., ...) const&&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) volatile&&> : true_type
struct is_function<Ret(Args..., ...) volatile&&> : ctl::true_type
{};
template<class Ret, class... Args>
struct is_function<Ret(Args..., ...) const volatile&&> : true_type
struct is_function<Ret(Args..., ...) const volatile&&> : ctl::true_type
{};
} // namespace ctl
+16 -16
View File
@@ -7,67 +7,67 @@
namespace ctl {
template<typename T>
struct is_integral : false_type
struct is_integral : ctl::false_type
{};
template<>
struct is_integral<bool> : true_type
struct is_integral<bool> : ctl::true_type
{};
template<>
struct is_integral<char> : true_type
struct is_integral<char> : ctl::true_type
{};
template<>
struct is_integral<signed char> : true_type
struct is_integral<signed char> : ctl::true_type
{};
template<>
struct is_integral<unsigned char> : true_type
struct is_integral<unsigned char> : ctl::true_type
{};
template<>
struct is_integral<short> : true_type
struct is_integral<short> : ctl::true_type
{};
template<>
struct is_integral<unsigned short> : true_type
struct is_integral<unsigned short> : ctl::true_type
{};
template<>
struct is_integral<int> : true_type
struct is_integral<int> : ctl::true_type
{};
template<>
struct is_integral<unsigned int> : true_type
struct is_integral<unsigned int> : ctl::true_type
{};
template<>
struct is_integral<long> : true_type
struct is_integral<long> : ctl::true_type
{};
template<>
struct is_integral<unsigned long> : true_type
struct is_integral<unsigned long> : ctl::true_type
{};
template<>
struct is_integral<long long> : true_type
struct is_integral<long long> : ctl::true_type
{};
template<>
struct is_integral<unsigned long long> : true_type
struct is_integral<unsigned long long> : ctl::true_type
{};
template<>
struct is_integral<char16_t> : true_type
struct is_integral<char16_t> : ctl::true_type
{};
template<>
struct is_integral<char32_t> : true_type
struct is_integral<char32_t> : ctl::true_type
{};
template<>
struct is_integral<wchar_t> : true_type
struct is_integral<wchar_t> : ctl::true_type
{};
template<typename T>
+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_IS_POLYMORPHIC_H_
#define CTL_IS_POLYMORPHIC_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_polymorphic : public ctl::integral_constant<bool, __is_polymorphic(T)>
{};
template<typename T>
inline constexpr bool is_polymorphic_v = __is_polymorphic(T);
} // namespace ctl
#endif // CTL_IS_POLYMORPHIC_H_
+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_IS_STANDARD_LAYOUT_H_
#define CTL_IS_STANDARD_LAYOUT_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_standard_layout
: public ctl::integral_constant<bool, __is_standard_layout(T)>
{};
template<typename T>
inline constexpr bool is_standard_layout_v = __is_standard_layout(T);
} // namespace ctl
#endif // CTL_IS_STANDARD_LAYOUT_H_
+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_IS_TRIVIAL_H_
#define CTL_IS_TRIVIAL_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_trivial : public ctl::integral_constant<bool, __is_trivial(T)>
{};
template<typename T>
inline constexpr bool is_trivial_v = __is_trivial(T);
} // namespace ctl
#endif // CTL_IS_TRIVIAL_H_
+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_IS_UNION_H_
#define CTL_IS_UNION_H_
#include "integral_constant.h"
namespace ctl {
template<typename T>
struct is_union : public ctl::integral_constant<bool, __is_union(T)>
{};
template<typename T>
inline constexpr bool is_union_v = __is_union(T);
} // namespace ctl
#endif // CTL_IS_UNION_H_
+237
View File
@@ -0,0 +1,237 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "istream.h"
#include "libc/fmt/conv.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "numeric_limits.h"
#include "string.h"
#include "utility.h"
namespace ctl {
istream cin(stdin);
istream::~istream() = default;
istream::istream(FILE* file) : ios(file), gcount_(0)
{
}
istream::istream(istream&& other) noexcept
: ios(other.file_), gcount_(other.gcount_)
{
other.file_ = nullptr;
other.gcount_ = 0;
}
istream&
istream::operator=(istream&& other) noexcept
{
if (this != &other) {
ios::operator=(ctl::move(other));
gcount_ = other.gcount_;
other.gcount_ = 0;
}
return *this;
}
istream&
istream::operator>>(char& c)
{
gcount_ = 0;
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit | failbit);
} else {
c = static_cast<char>(ch);
gcount_ = 1;
}
return *this;
}
istream&
istream::operator>>(int& n)
{
if (fscanf(file_, "%d", &n) != 1)
setstate(failbit);
return *this;
}
istream&
istream::operator>>(long& n)
{
if (fscanf(file_, "%ld", &n) != 1)
setstate(failbit);
return *this;
}
istream&
istream::operator>>(double& d)
{
if (fscanf(file_, "%f", &d) != 1)
setstate(failbit);
return *this;
}
istream&
istream::operator>>(ctl::string& s)
{
char buffer[1024];
if (fscanf(file_, "%1023s", buffer) == 1) {
s = buffer;
} else {
setstate(failbit);
}
return *this;
}
istream&
istream::operator>>(bool& b)
{
char buffer[6];
if (fscanf(file_, "%5s", buffer) == 1) {
if (strcmp(buffer, "true") == 0 || strcmp(buffer, "1") == 0) {
b = true;
} else if (strcmp(buffer, "false") == 0 || strcmp(buffer, "0") == 0) {
b = false;
} else {
setstate(failbit);
}
} else {
setstate(failbit);
}
return *this;
}
istream&
istream::operator>>(istream& (*manip)(istream&))
{
return manip(*this);
}
int
istream::get()
{
gcount_ = 0;
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit);
} else {
gcount_ = 1;
}
return ch;
}
istream&
istream::get(char& c)
{
int ch = get();
if (ch != EOF)
c = static_cast<char>(ch);
return *this;
}
istream&
istream::getline(char* s, streamsize n)
{
return getline(s, n, '\n');
}
istream&
istream::getline(char* s, streamsize n, char delim)
{
gcount_ = 0;
if (n <= 0) {
setstate(failbit);
return *this;
}
while (gcount_ < n - 1) {
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit);
break;
}
if (ch == delim)
break;
s[gcount_++] = static_cast<char>(ch);
}
s[gcount_] = '\0';
if (gcount_ == 0)
setstate(failbit);
return *this;
}
istream&
istream::read(char* s, streamsize n)
{
gcount_ = fread(s, 1, n, file_);
if (gcount_ < n) {
setstate(eofbit);
if (gcount_ == 0)
setstate(failbit);
}
return *this;
}
istream::streamsize
istream::gcount() const
{
return gcount_;
}
int
istream::peek()
{
int ch = fgetc(file_);
if (ch != EOF) {
ungetc(ch, file_);
} else {
setstate(eofbit);
}
return ch;
}
istream&
istream::ignore(streamsize n, int delim)
{
gcount_ = 0;
while (gcount_ < n) {
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit);
break;
}
++gcount_;
if (ch == delim)
break;
}
return *this;
}
istream&
ws(istream& is)
{
int ch;
while ((ch = is.peek()) != EOF && isspace(ch))
is.get();
return is;
}
} // namespace ctl
+53
View File
@@ -0,0 +1,53 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ISTREAM_H_
#define CTL_ISTREAM_H_
#include "ios.h"
namespace ctl {
struct string;
class istream : public ios
{
public:
istream() = delete;
explicit istream(FILE*);
virtual ~istream();
istream& operator>>(char&);
istream& operator>>(int&);
istream& operator>>(long&);
istream& operator>>(double&);
istream& operator>>(bool&);
istream& operator>>(ctl::string&);
istream& operator>>(istream& (*)(istream&));
int get();
istream& get(char&);
istream& getline(char*, streamsize);
istream& getline(char*, streamsize, char);
istream& read(char*, streamsize);
streamsize gcount() const;
int peek();
istream& ignore(streamsize = 1, int = -1);
istream(istream&&) noexcept;
istream& operator=(istream&&) noexcept;
private:
streamsize gcount_;
istream(const istream&) = delete;
istream& operator=(const istream&) = delete;
};
extern istream cin;
istream&
ws(istream& is);
} // namespace ctl
#endif // CTL_ISTREAM_H_
+221
View File
@@ -0,0 +1,221 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "istringstream.h"
#include "libc/fmt/conv.h"
#include "libc/str/str.h"
namespace ctl {
istringstream::istringstream() : buffer_(), read_pos_(0)
{
}
istringstream::istringstream(const ctl::string_view& str)
: buffer_(str), read_pos_(0)
{
}
ctl::string
istringstream::str() const
{
return buffer_;
}
void
istringstream::str(const ctl::string& s)
{
buffer_ = s;
read_pos_ = 0;
clear();
}
istringstream&
istringstream::operator>>(char& c)
{
if (good() && read_pos_ < buffer_.size()) {
c = buffer_[read_pos_++];
} else {
setstate(ios_base::failbit);
}
return *this;
}
istringstream&
istringstream::operator>>(char* s)
{
if (!good())
return *this;
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
++read_pos_;
size_t start = read_pos_;
while (read_pos_ < buffer_.size() && !isspace(buffer_[read_pos_])) {
s[read_pos_ - start] = buffer_[read_pos_];
++read_pos_;
}
s[read_pos_ - start] = '\0';
if (start == read_pos_) {
setstate(ios_base::failbit);
} else if (read_pos_ == buffer_.size()) {
setstate(ios_base::eofbit);
}
return *this;
}
istringstream&
istringstream::operator>>(ctl::string& s)
{
if (!good())
return *this;
s.clear();
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
++read_pos_;
while (read_pos_ < buffer_.size() && !isspace(buffer_[read_pos_])) {
s.push_back(buffer_[read_pos_]);
++read_pos_;
}
if (s.empty()) {
setstate(ios_base::failbit);
} else if (read_pos_ == buffer_.size()) {
setstate(ios_base::eofbit);
}
return *this;
}
template<typename T>
istringstream&
istringstream::read_numeric(T& value)
{
if (!good())
return *this;
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
++read_pos_;
// size_t start = read_pos_;
bool is_negative = false;
if (read_pos_ < buffer_.size() &&
(buffer_[read_pos_] == '-' || buffer_[read_pos_] == '+')) {
is_negative = (buffer_[read_pos_] == '-');
++read_pos_;
}
T result = 0;
bool valid = false;
while (read_pos_ < buffer_.size() && isdigit(buffer_[read_pos_])) {
result = result * 10 + (buffer_[read_pos_] - '0');
++read_pos_;
valid = true;
}
if (valid) {
value = is_negative ? -result : result;
if (read_pos_ == buffer_.size())
setstate(ios_base::eofbit);
} else {
setstate(ios_base::failbit);
}
return *this;
}
istringstream&
istringstream::operator>>(short& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(unsigned short& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(int& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(unsigned int& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(long& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(unsigned long& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(float& f)
{
if (!good())
return *this;
char* end;
f = strtof(buffer_.c_str() + read_pos_, &end);
if (end == buffer_.c_str() + read_pos_) {
setstate(ios_base::failbit);
} else {
read_pos_ = end - buffer_.c_str();
if (read_pos_ == buffer_.size())
setstate(ios_base::eofbit);
}
return *this;
}
istringstream&
istringstream::operator>>(double& d)
{
if (!good())
return *this;
char* end;
d = strtod(buffer_.c_str() + read_pos_, &end);
if (end == buffer_.c_str() + read_pos_) {
setstate(ios_base::failbit);
} else {
read_pos_ = end - buffer_.c_str();
if (read_pos_ == buffer_.size())
setstate(ios_base::eofbit);
}
return *this;
}
} // namespace ctl
+41
View File
@@ -0,0 +1,41 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ISTRINGSTREAM_H_
#define CTL_ISTRINGSTREAM_H_
#include "ios_base.h"
#include "string.h"
namespace ctl {
class istringstream : public ios_base
{
public:
istringstream();
explicit istringstream(const ctl::string_view&);
string str() const;
void str(const string&);
istringstream& operator>>(char&);
istringstream& operator>>(char*);
istringstream& operator>>(ctl::string&);
istringstream& operator>>(short&);
istringstream& operator>>(unsigned short&);
istringstream& operator>>(int&);
istringstream& operator>>(unsigned int&);
istringstream& operator>>(long&);
istringstream& operator>>(unsigned long&);
istringstream& operator>>(float&);
istringstream& operator>>(double&);
private:
ctl::string buffer_;
size_t read_pos_;
template<typename T>
istringstream& read_numeric(T&);
};
} // namespace ctl
#endif // CTL_ISTRINGSTREAM_H_
+22 -11
View File
@@ -2,12 +2,33 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ITERATOR_TRAITS_H_
#define CTL_ITERATOR_TRAITS_H_
#include "iterator.h"
#include "utility.h"
#include "void_t.h"
namespace ctl {
template<class Iterator>
template<typename Iterator, typename = void>
struct iterator_traits
{};
template<typename T>
struct iterator_traits<T*>
{
using difference_type = ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category = ctl::random_access_iterator_tag;
};
template<typename Iterator>
struct iterator_traits<Iterator,
ctl::void_t<typename Iterator::iterator_category,
typename Iterator::value_type,
typename Iterator::difference_type,
typename Iterator::pointer,
typename Iterator::reference>>
{
using iterator_category = typename Iterator::iterator_category;
using value_type = typename Iterator::value_type;
@@ -16,16 +37,6 @@ struct iterator_traits
using reference = typename Iterator::reference;
};
template<class T>
struct iterator_traits<T*>
{
using iterator_category = void*; // We don't actually use this
using value_type = T;
using difference_type = ptrdiff_t;
using pointer = T*;
using reference = T&;
};
} // namespace ctl
#endif // CTL_ITERATOR_TRAITS_H_
+14 -14
View File
@@ -152,12 +152,12 @@ class map
Value& operator[](const Key& key)
{
return ((data_.insert(make_pair(key, Value()))).first)->second;
return ((data_.insert(ctl::make_pair(key, Value()))).first)->second;
}
Value& operator[](Key&& key)
{
return ((data_.insert(make_pair(ctl::move(key), Value()))).first)
return ((data_.insert(ctl::make_pair(ctl::move(key), Value()))).first)
->second;
}
@@ -165,7 +165,7 @@ class map
{
auto it = find(key);
if (it == end())
throw ctl::out_of_range("out of range");
throw ctl::out_of_range();
return it->second;
}
@@ -173,7 +173,7 @@ class map
{
auto it = find(key);
if (it == end())
throw ctl::out_of_range("out of range");
throw ctl::out_of_range();
return it->second;
}
@@ -244,7 +244,7 @@ class map
size_type erase(const Key& key)
{
return data_.erase(make_pair(key, Value()));
return data_.erase(ctl::make_pair(key, Value()));
}
void swap(map& other) noexcept
@@ -259,47 +259,47 @@ class map
iterator find(const Key& key)
{
return data_.find(make_pair(key, Value()));
return data_.find(ctl::make_pair(key, Value()));
}
const_iterator find(const Key& key) const
{
return data_.find(make_pair(key, Value()));
return data_.find(ctl::make_pair(key, Value()));
}
size_type count(const Key& key) const
{
return data_.count(make_pair(key, Value()));
return data_.count(ctl::make_pair(key, Value()));
}
iterator lower_bound(const Key& key)
{
return data_.lower_bound(make_pair(key, Value()));
return data_.lower_bound(ctl::make_pair(key, Value()));
}
const_iterator lower_bound(const Key& key) const
{
return data_.lower_bound(make_pair(key, Value()));
return data_.lower_bound(ctl::make_pair(key, Value()));
}
iterator upper_bound(const Key& key)
{
return data_.upper_bound(make_pair(key, Value()));
return data_.upper_bound(ctl::make_pair(key, Value()));
}
const_iterator upper_bound(const Key& key) const
{
return data_.upper_bound(make_pair(key, Value()));
return data_.upper_bound(ctl::make_pair(key, Value()));
}
ctl::pair<iterator, iterator> equal_range(const Key& key)
{
return data_.equal_range(make_pair(key, Value()));
return data_.equal_range(ctl::make_pair(key, Value()));
}
ctl::pair<const_iterator, const_iterator> equal_range(const Key& key) const
{
return data_.equal_range(make_pair(key, Value()));
return data_.equal_range(ctl::make_pair(key, Value()));
}
key_compare key_comp() const
+8 -4
View File
@@ -11,17 +11,20 @@ class mutex
public:
mutex()
{
pthread_mutex_init(&m_, nullptr);
if (pthread_mutex_init(&m_, nullptr))
__builtin_trap();
}
~mutex()
{
pthread_mutex_destroy(&m_);
if (pthread_mutex_destroy(&m_))
__builtin_trap();
}
void lock()
{
pthread_mutex_lock(&m_);
if (pthread_mutex_lock(&m_))
__builtin_trap();
}
bool try_lock()
@@ -31,7 +34,8 @@ class mutex
void unlock()
{
pthread_mutex_unlock(&m_);
if (pthread_mutex_unlock(&m_))
__builtin_trap();
}
// Delete copy constructor and assignment operator
+219
View File
@@ -0,0 +1,219 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ostream.h"
#include "dubble.h"
#include "libc/fmt/itoa.h"
#include "libc/stdio/stdio.h"
#include "string_view.h"
namespace ctl {
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
ostream cout(stdout);
ostream cerr(stderr);
ostream::~ostream() = default;
ostream::ostream(FILE* file) : ios(file)
{
}
ostream::ostream(ostream&& other) noexcept : ios(other.file_)
{
other.file_ = nullptr;
}
ostream&
ostream::operator=(ostream&& other) noexcept
{
if (this != &other) {
file_ = other.file_;
other.file_ = nullptr;
}
return *this;
}
ostream&
ostream::operator<<(const char* str)
{
if (good() && str)
if (fputs(str, file_) < 0)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(char c)
{
if (good())
if (fputc(c, file_) == EOF)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(int n)
{
if (good()) {
char buf[12];
FormatInt32(buf, n);
if (fputs(buf, file_) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(unsigned n)
{
if (good()) {
char buf[12];
FormatUint32(buf, n);
if (fputs(buf, file_) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(long n)
{
if (good()) {
char buf[21];
FormatInt64(buf, n);
if (fputs(buf, file_) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(unsigned long n)
{
if (good()) {
char buf[21];
FormatUint64(buf, n);
if (fputs(buf, file_) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(float f)
{
if (good()) {
char buf[128];
double_conversion::StringBuilder b(buf, sizeof(buf));
kDoubleToPrintfG.ToShortestSingle(f, &b);
b.Finalize();
if (fputs(buf, file_) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(double d)
{
if (good()) {
char buf[128];
double_conversion::StringBuilder b(buf, sizeof(buf));
kDoubleToPrintfG.ToShortest(d, &b);
b.Finalize();
if (fputs(buf, file_) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(const string_view& s)
{
if (good() && s.size())
if (!fwrite(s.data(), s.size(), 1, file_))
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(bool b)
{
if (good()) {
const char* value =
(flags() & boolalpha) ? (b ? "true" : "false") : (b ? "1" : "0");
if (fputs(value, file_) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(ostream& (*manip)(ostream&))
{
return manip(*this);
}
ostream&
ostream::put(char c)
{
if (good())
if (fputc(c, file_) == EOF)
setstate(badbit);
return *this;
}
ostream&
ostream::write(const char* s, streamsize n)
{
if (good())
if (fwrite(s, 1, n, file_) != static_cast<size_t>(n))
setstate(badbit);
return *this;
}
ostream&
ostream::flush()
{
if (good())
if (fflush(file_) != 0)
setstate(badbit);
return *this;
}
ostream&
endl(ostream& os)
{
return os.put('\n').flush();
}
ostream&
ends(ostream& os)
{
return os.put('\0');
}
ostream&
flush(ostream& os)
{
return os.flush();
}
} // namespace ctl
+56
View File
@@ -0,0 +1,56 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_OSTREAM_H_
#define CTL_OSTREAM_H_
#include "ios.h"
namespace ctl {
struct string_view;
class ostream : public ios
{
public:
ostream() = delete;
explicit ostream(FILE*);
virtual ~ostream();
ostream& operator<<(const char*);
ostream& operator<<(bool);
ostream& operator<<(char);
ostream& operator<<(int);
ostream& operator<<(unsigned);
ostream& operator<<(long);
ostream& operator<<(unsigned long);
ostream& operator<<(float);
ostream& operator<<(double);
ostream& operator<<(const ctl::string_view&);
ostream& operator<<(ostream& (*)(ostream&));
ostream& put(char);
ostream& write(const char*, streamsize);
ostream& flush();
ostream(ostream&&) noexcept;
ostream& operator=(ostream&&) noexcept;
private:
ostream(const ostream&) = delete;
ostream& operator=(const ostream&) = delete;
};
extern ostream cout;
extern ostream cerr;
ostream&
endl(ostream&);
ostream&
ends(ostream&);
ostream&
flush(ostream&);
} // namespace ctl
#endif // CTL_OSTREAM_H_
+150
View File
@@ -0,0 +1,150 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ostringstream.h"
#include "dubble.h"
#include "libc/fmt/itoa.h"
namespace ctl {
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
ostringstream::ostringstream() : buffer_(), write_pos_(0)
{
}
ostringstream::ostringstream(const string_view& str)
: buffer_(str), write_pos_(0)
{
}
string
ostringstream::str() const
{
return buffer_;
}
void
ostringstream::str(const string& s)
{
buffer_ = s;
write_pos_ = 0;
}
void
ostringstream::clear()
{
ios_base::clear();
}
ostringstream&
ostringstream::operator<<(char c)
{
if (good()) {
if (write_pos_ < buffer_.size()) {
buffer_[write_pos_++] = c;
} else {
buffer_.push_back(c);
++write_pos_;
}
}
return *this;
}
ostringstream&
ostringstream::operator<<(const string_view& s)
{
if (good()) {
if (write_pos_ + s.size() <= buffer_.size()) {
buffer_.replace(write_pos_, s.size(), s);
} else {
buffer_.replace(write_pos_, buffer_.size() - write_pos_, s);
buffer_.append(s.substr(buffer_.size() - write_pos_));
}
write_pos_ += s.size();
}
return *this;
}
ostringstream&
ostringstream::operator<<(int n)
{
if (good()) {
char buf[12];
*this << string_view(buf, FormatInt32(buf, n) - buf);
}
return *this;
}
ostringstream&
ostringstream::operator<<(unsigned n)
{
if (good()) {
char buf[12];
*this << string_view(buf, FormatUint32(buf, n) - buf);
}
return *this;
}
ostringstream&
ostringstream::operator<<(long n)
{
if (good()) {
char buf[21];
*this << string_view(buf, FormatInt64(buf, n) - buf);
}
return *this;
}
ostringstream&
ostringstream::operator<<(unsigned long n)
{
if (good()) {
char buf[21];
*this << string_view(buf, FormatUint64(buf, n) - buf);
}
return *this;
}
ostringstream&
ostringstream::operator<<(float f)
{
if (good()) {
char buf[128];
double_conversion::StringBuilder b(buf, sizeof(buf));
kDoubleToPrintfG.ToShortestSingle(f, &b);
b.Finalize();
*this << string_view(buf);
}
return *this;
}
ostringstream&
ostringstream::operator<<(double d)
{
if (good()) {
char buf[128];
double_conversion::StringBuilder b(buf, sizeof(buf));
kDoubleToPrintfG.ToShortest(d, &b);
b.Finalize();
*this << string_view(buf);
}
return *this;
}
} // namespace ctl
+36
View File
@@ -0,0 +1,36 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_OSTRINGSTREAM_H_
#define CTL_OSTRINGSTREAM_H_
#include "ios_base.h"
#include "string.h"
namespace ctl {
class ostringstream : public ios_base
{
public:
ostringstream();
explicit ostringstream(const ctl::string_view&);
ctl::string str() const;
void str(const ctl::string& s);
void clear();
ostringstream& operator<<(char);
ostringstream& operator<<(const ctl::string_view&);
ostringstream& operator<<(int);
ostringstream& operator<<(unsigned int);
ostringstream& operator<<(long);
ostringstream& operator<<(unsigned long);
ostringstream& operator<<(float);
ostringstream& operator<<(double);
private:
ctl::string buffer_;
size_t write_pos_;
};
} // namespace ctl
#endif // CTL_OSTRINGSTREAM_H_
+1 -1
View File
@@ -6,7 +6,7 @@
namespace ctl {
class out_of_range : public exception
class out_of_range : public ctl::exception
{
public:
out_of_range() noexcept = default;
+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_REQUIRE_INPUT_ITERATOR_H_
#define CTL_REQUIRE_INPUT_ITERATOR_H_
#include "enable_if.h"
#include "is_convertible.h"
#include "iterator.h"
#include "iterator_traits.h"
namespace ctl {
template<typename InputIt>
using require_input_iterator = typename ctl::enable_if<
ctl::is_convertible<typename ctl::iterator_traits<InputIt>::iterator_category,
ctl::input_iterator_tag>::value>::type;
} // namespace ctl
#endif /* CTL_REQUIRE_INPUT_ITERATOR_H_ */
+6 -5
View File
@@ -13,11 +13,12 @@ class reverse_iterator
public:
using iterator_type = Iterator;
using iterator_category =
typename iterator_traits<Iterator>::iterator_category;
using value_type = typename iterator_traits<Iterator>::value_type;
using difference_type = typename iterator_traits<Iterator>::difference_type;
using pointer = typename iterator_traits<Iterator>::pointer;
using reference = typename iterator_traits<Iterator>::reference;
typename ctl::iterator_traits<Iterator>::iterator_category;
using value_type = typename ctl::iterator_traits<Iterator>::value_type;
using difference_type =
typename ctl::iterator_traits<Iterator>::difference_type;
using pointer = typename ctl::iterator_traits<Iterator>::pointer;
using reference = typename ctl::iterator_traits<Iterator>::reference;
constexpr reverse_iterator() : current()
{
+15 -14
View File
@@ -8,7 +8,7 @@
namespace ctl {
template<typename Key, typename Compare = less<Key>>
template<typename Key, typename Compare = ctl::less<Key>>
class set
{
struct rbtree
@@ -381,12 +381,12 @@ class set
size_ = 0;
}
pair<iterator, bool> insert(value_type&& value)
ctl::pair<iterator, bool> insert(value_type&& value)
{
return insert_node(new node_type(ctl::move(value)));
}
pair<iterator, bool> insert(const value_type& value)
ctl::pair<iterator, bool> insert(const value_type& value)
{
return insert_node(new node_type(value));
}
@@ -415,7 +415,7 @@ class set
}
template<class... Args>
pair<iterator, bool> emplace(Args&&... args)
ctl::pair<iterator, bool> emplace(Args&&... args)
{
value_type value(ctl::forward<Args>(args)...);
return insert(ctl::move(value));
@@ -451,12 +451,13 @@ class set
ctl::swap(size_, other.size_);
}
pair<iterator, iterator> equal_range(const key_type& key)
ctl::pair<iterator, iterator> equal_range(const key_type& key)
{
return { iterator(get_floor(key)), iterator(get_ceiling(key)) };
}
pair<const_iterator, const_iterator> equal_range(const key_type& key) const
ctl::pair<const_iterator, const_iterator> equal_range(
const key_type& key) const
{
return { const_iterator(get_floor(key)),
const_iterator(get_ceiling(key)) };
@@ -613,7 +614,7 @@ class set
return result;
}
pair<iterator, bool> insert_node(node_type* node)
ctl::pair<iterator, bool> insert_node(node_type* node)
{
if (root_ == nullptr) {
root_ = node;
@@ -878,7 +879,7 @@ class set
Compare comp_;
};
template<class Key, typename Compare = less<Key>>
template<class Key, typename Compare = ctl::less<Key>>
bool
operator==(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
@@ -893,7 +894,7 @@ operator==(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
return true;
}
template<class Key, typename Compare = less<Key>>
template<class Key, typename Compare = ctl::less<Key>>
bool
operator<(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
@@ -908,35 +909,35 @@ operator<(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
return i == lhs.end() && j != rhs.end();
}
template<class Key, typename Compare = less<Key>>
template<class Key, typename Compare = ctl::less<Key>>
bool
operator!=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return !(lhs == rhs);
}
template<class Key, typename Compare = less<Key>>
template<class Key, typename Compare = ctl::less<Key>>
bool
operator<=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return !(rhs < lhs);
}
template<class Key, typename Compare = less<Key>>
template<class Key, typename Compare = ctl::less<Key>>
bool
operator>(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return rhs < lhs;
}
template<class Key, typename Compare = less<Key>>
template<class Key, typename Compare = ctl::less<Key>>
bool
operator>=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return !(lhs < rhs);
}
template<class Key, typename Compare = less<Key>>
template<class Key, typename Compare = ctl::less<Key>>
void
swap(set<Key, Compare>& lhs, set<Key, Compare>& rhs) noexcept;
+80 -25
View File
@@ -9,7 +9,7 @@ namespace ctl {
class string;
string strcat(string_view, string_view) noexcept __wur;
ctl::string strcat(ctl::string_view, ctl::string_view) noexcept __wur;
namespace __ {
@@ -66,7 +66,7 @@ class string
*(((size_t*)blob) + 2) = __::sso_max << (sizeof(size_t) - 1) * 8;
}
string(const string_view s) noexcept
string(const ctl::string_view s) noexcept
{
if (s.n <= __::sso_max) {
__builtin_memcpy(blob, s.p, s.n);
@@ -89,7 +89,7 @@ class string
}
string(const char* const p) noexcept
: string(string_view(p, __builtin_strlen(p)))
: string(ctl::string_view(p, __builtin_strlen(p)))
{
}
@@ -104,7 +104,7 @@ class string
}
string(const char* const p, const size_t n) noexcept
: string(string_view(p, n))
: string(ctl::string_view(p, n))
{
}
@@ -125,17 +125,17 @@ class string
void append(char, size_t) noexcept;
void append(unsigned long) noexcept;
void append(const void*, size_t) noexcept;
string& insert(size_t, string_view) noexcept;
string& insert(size_t, ctl::string_view) noexcept;
string& erase(size_t = 0, size_t = npos) noexcept;
string substr(size_t = 0, size_t = npos) const noexcept;
string& replace(size_t, size_t, string_view) noexcept;
bool operator==(string_view) const noexcept;
bool operator!=(string_view) const noexcept;
bool contains(string_view) const noexcept;
bool ends_with(string_view) const noexcept;
bool starts_with(string_view) const noexcept;
string& replace(size_t, size_t, ctl::string_view) noexcept;
bool operator==(ctl::string_view) const noexcept;
bool operator!=(ctl::string_view) const noexcept;
bool contains(ctl::string_view) const noexcept;
bool ends_with(ctl::string_view) const noexcept;
bool starts_with(ctl::string_view) const noexcept;
size_t find(char, size_t = 0) const noexcept;
size_t find(string_view, size_t = 0) const noexcept;
size_t find(ctl::string_view, size_t = 0) const noexcept;
void swap(string& s) noexcept
{
@@ -302,14 +302,14 @@ class string
append(ch);
}
void append(const string_view s) noexcept
void append(const ctl::string_view s) noexcept
{
append(s.p, s.n);
}
operator string_view() const noexcept
operator ctl::string_view() const noexcept
{
return string_view(data(), size());
return ctl::string_view(data(), size());
}
string& operator=(const char* s) noexcept
@@ -319,7 +319,7 @@ class string
return *this;
}
string& operator=(const string_view s) noexcept
string& operator=(const ctl::string_view s) noexcept
{
clear();
append(s);
@@ -332,38 +332,66 @@ class string
return *this;
}
string& operator+=(const string_view s) noexcept
string& operator+=(const char* s) noexcept
{
append(s);
return *this;
}
string operator+(const string_view s) const noexcept
string& operator+=(const ctl::string s) noexcept
{
append(s);
return *this;
}
string& operator+=(const ctl::string_view s) noexcept
{
append(s);
return *this;
}
string operator+(const char c) const noexcept
{
char s[2] = { c };
return strcat(*this, s);
}
string operator+(const char* s) const noexcept
{
return strcat(*this, s);
}
int compare(const string_view s) const noexcept
string operator+(const string& s) const noexcept
{
return strcat(*this, s);
}
string operator+(const ctl::string_view s) const noexcept
{
return strcat(*this, s);
}
int compare(const ctl::string_view s) const noexcept
{
return strcmp(*this, s);
}
bool operator<(const string_view s) const noexcept
bool operator<(const ctl::string_view s) const noexcept
{
return compare(s) < 0;
}
bool operator<=(const string_view s) const noexcept
bool operator<=(const ctl::string_view s) const noexcept
{
return compare(s) <= 0;
}
bool operator>(const string_view s) const noexcept
bool operator>(const ctl::string_view s) const noexcept
{
return compare(s) > 0;
}
bool operator>=(const string_view s) const noexcept
bool operator>=(const ctl::string_view s) const noexcept
{
return compare(s) >= 0;
}
@@ -371,7 +399,7 @@ class string
private:
void destroy_big() noexcept;
void init_big(const string&) noexcept;
void init_big(string_view) noexcept;
void init_big(ctl::string_view) noexcept;
void init_big(size_t, char) noexcept;
__attribute__((__always_inline__)) bool isbig() const noexcept
@@ -395,7 +423,7 @@ class string
__b.c = c2 | ~__::big_mask;
}
friend string strcat(string_view, string_view) noexcept;
friend string strcat(ctl::string_view, ctl::string_view) noexcept;
union
{
@@ -409,6 +437,33 @@ static_assert(sizeof(string) == __::string_size);
static_assert(sizeof(__::small_string) == __::string_size);
static_assert(sizeof(__::big_string) == __::string_size);
ctl::string
to_string(int) noexcept;
ctl::string
to_string(long) noexcept;
ctl::string
to_string(long long) noexcept;
ctl::string
to_string(unsigned) noexcept;
ctl::string
to_string(unsigned long) noexcept;
ctl::string
to_string(unsigned long long) noexcept;
ctl::string
to_string(float) noexcept;
ctl::string
to_string(double) noexcept;
ctl::string
to_string(long double) noexcept;
} // namespace ctl
#pragma GCC diagnostic push
+109
View File
@@ -0,0 +1,109 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "dubble.h"
#include "libc/fmt/itoa.h"
#include "libc/math.h"
#include "string.h"
#include "third_party/gdtoa/gdtoa.h"
namespace ctl {
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
string
to_string(int value) noexcept
{
char buf[12];
return { buf, FormatInt32(buf, value) - buf };
}
string
to_string(unsigned value) noexcept
{
char buf[12];
return { buf, FormatUint32(buf, value) - buf };
}
string
to_string(long value) noexcept
{
char buf[21];
return { buf, FormatInt64(buf, value) - buf };
}
string
to_string(unsigned long value) noexcept
{
char buf[21];
return { buf, FormatUint64(buf, value) - buf };
}
string
to_string(long long value) noexcept
{
char buf[21];
return { buf, FormatInt64(buf, value) - buf };
}
string
to_string(unsigned long long value) noexcept
{
char buf[21];
return { buf, FormatUint64(buf, value) - buf };
}
string
to_string(float value) noexcept
{
char buf[128];
double_conversion::StringBuilder b(buf, sizeof(buf));
kDoubleToPrintfG.ToShortestSingle(value, &b);
b.Finalize();
return string(buf);
}
string
to_string(double value) noexcept
{
char buf[128];
double_conversion::StringBuilder b(buf, sizeof(buf));
kDoubleToPrintfG.ToShortest(value, &b);
b.Finalize();
return string(buf);
}
string
to_string(long double value) noexcept
{
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return to_string((double)value);
#else
char buf[128];
#if LDBL_MANT_DIG == 113
g_Qfmt_p(buf, &value, 16, 128, NIK(2, 0, 0));
#elif LDBL_MANT_DIG == 64
g_xfmt_p(buf, &value, 16, 128, NIK(2, 0, 0));
#else
#error "unsupported long double"
#endif
return string(buf);
#endif
}
} // namespace ctl
+3 -3
View File
@@ -1,7 +1,7 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_UTILITY_H_
#define COSMOPOLITAN_CTL_UTILITY_H_
#ifndef CTL_UTILITY_H_
#define CTL_UTILITY_H_
#include "remove_reference.h"
namespace ctl {
@@ -66,4 +66,4 @@ declval() noexcept;
} // namespace ctl
#endif // COSMOPOLITAN_CTL_UTILITY_H_
#endif // CTL_UTILITY_H_
+14 -8
View File
@@ -15,6 +15,7 @@
#include "move_backward.h"
#include "move_iterator.h"
#include "out_of_range.h"
#include "require_input_iterator.h"
#include "reverse_iterator.h"
#include "uninitialized_fill.h"
#include "uninitialized_fill_n.h"
@@ -65,7 +66,7 @@ class vector
resize(count);
}
template<class InputIt>
template<class InputIt, typename = ctl::require_input_iterator<InputIt>>
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator())
: alloc_(alloc), data_(nullptr), size_(0), capacity_(0)
{
@@ -173,7 +174,7 @@ class vector
size_ = count;
}
template<class InputIt>
template<class InputIt, typename = ctl::require_input_iterator<InputIt>>
void assign(InputIt first, InputIt last)
{
clear();
@@ -189,24 +190,28 @@ class vector
reference at(size_type pos)
{
if (pos >= size_)
throw ctl::out_of_range("out of range");
throw ctl::out_of_range();
return data_[pos];
}
const_reference at(size_type pos) const
{
if (pos >= size_)
throw ctl::out_of_range("out of range");
throw ctl::out_of_range();
return data_[pos];
}
reference operator[](size_type pos)
{
if (pos >= size_)
__builtin_trap();
return data_[pos];
}
const_reference operator[](size_type pos) const
{
if (pos >= size_)
__builtin_trap();
return data_[pos];
}
@@ -368,7 +373,7 @@ class vector
return it;
}
template<class InputIt>
template<class InputIt, typename = ctl::require_input_iterator<InputIt>>
iterator insert(const_iterator pos, InputIt first, InputIt last)
{
difference_type count = ctl::distance(first, last);
@@ -406,16 +411,17 @@ class vector
return erase(pos, pos + 1);
}
iterator erase(const_iterator first, const_iterator last)
constexpr iterator erase(const_iterator first, const_iterator last)
{
difference_type index = first - begin();
difference_type count = last - first;
iterator it = begin() + index;
ctl::move(it + count, end(), it);
for (iterator move_it = it + count; move_it != end(); ++move_it, ++it)
*it = ctl::move(*move_it);
for (difference_type i = 0; i < count; ++i)
ctl::allocator_traits<Allocator>::destroy(alloc_, end() - i - 1);
size_ -= count;
return it;
return begin() + index;
}
void push_back(const T& value)
-10
View File
@@ -53,15 +53,5 @@ int prctl(int operation, ...) {
rc = enosys();
}
#if SYSDEBUG
if (operation == PR_CAPBSET_READ || operation == PR_CAPBSET_DROP) {
STRACE("prctl(%s, %s) → %d% m", DescribePrctlOperation(operation),
DescribeCapability(a), rc);
} else {
STRACE("prctl(%s, %p, %p, %p, %p) → %d% m",
DescribePrctlOperation(operation), a, b, c, d, rc);
}
#endif
return rc;
}
+1 -1
View File
@@ -4,7 +4,7 @@
#define __COSMOPOLITAN_MAJOR__ 3
#define __COSMOPOLITAN_MINOR__ 5
#define __COSMOPOLITAN_PATCH__ 2
#define __COSMOPOLITAN_PATCH__ 4
#define __COSMOPOLITAN__ \
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
__COSMOPOLITAN_PATCH__)
+3 -3
View File
@@ -1,5 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_INTERNAL_H_
#define COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_INTERNAL_H_
#ifndef COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_H_
#define COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_H_
#include "libc/mem/alloca.h"
#include "libc/nexgen32e/stackframe.h"
COSMOPOLITAN_C_START_
@@ -8,4 +8,4 @@ const char *DescribeBacktrace(char[160], const struct StackFrame *) libcesque;
#define DescribeBacktrace(x) DescribeBacktrace(alloca(160), x)
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_INTERNAL_H_ */
#endif /* COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_H_ */
-4
View File
@@ -13,7 +13,6 @@ const char *DescribeFlags(char *, size_t, const struct DescribeFlags *, size_t,
const char *DescribeArchPrctlCode(char[12], int) libcesque;
const char *DescribeCancelState(char[12], int, int *) libcesque;
const char *DescribeCapability(char[32], int) libcesque;
const char *DescribeClockName(char[32], int) libcesque;
const char *DescribeControlKeyState(char[64], uint32_t) libcesque;
const char *DescribeDirfd(char[12], int) libcesque;
@@ -47,7 +46,6 @@ const char *DescribeOpenFlags(char[128], int) libcesque;
const char *DescribeOpenMode(char[15], int, int) libcesque;
const char *DescribePersonalityFlags(char[128], int) libcesque;
const char *DescribePollFlags(char[64], int) libcesque;
const char *DescribePrctlOperation(int) libcesque;
const char *DescribeProtFlags(char[48], int) libcesque;
const char *DescribePtrace(char[12], int) libcesque;
const char *DescribePtraceEvent(char[32], int) libcesque;
@@ -69,9 +67,7 @@ const char *DescribeVirtualKeyCode(char[32], uint32_t) libcesque;
const char *DescribeWhence(char[12], int) libcesque;
const char *DescribeWhichPrio(char[12], int) libcesque;
#define DescribeArchPrctlCode(x) DescribeArchPrctlCode(alloca(12), x)
#define DescribeCancelState(x, y) DescribeCancelState(alloca(12), x, y)
#define DescribeCapability(x) DescribeCapability(alloca(32), x)
#define DescribeClockName(x) DescribeClockName(alloca(32), x)
#define DescribeControlKeyState(x) DescribeControlKeyState(alloca(64), x)
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
-1
View File
@@ -39,7 +39,6 @@ struct AddrSize {
extern struct Maps __maps;
void *randaddr(void);
void __maps_init(void);
void __maps_lock(void);
void __maps_check(void);
+77 -68
View File
@@ -21,6 +21,7 @@
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
@@ -187,10 +188,10 @@ int __munmap(char *addr, size_t size, bool untrack_only) {
!size || (uintptr_t)addr + size < size)
return einval();
// untrack and delete mapping
// untrack mappings
int rc = 0;
struct Dll *delete = 0;
__maps_lock();
StartOver:;
struct Map *map = __maps.maps;
struct Map **prev = &__maps.maps;
while (map) {
@@ -202,30 +203,10 @@ StartOver:;
if (addr <= map_addr && addr + PGUP(size) >= map_addr + PGUP(map_size)) {
// remove mapping completely
dll_remove(&__maps.used, &map->elem);
dll_make_first(&delete, &map->elem);
*prev = next;
__maps.pages -= (map_size + pagesz - 1) / pagesz;
__maps.count -= 1;
if (untrack_only) {
__maps_free(map);
__maps_check();
} else {
__maps_unlock();
if (!IsWindows()) {
ASSERT(addr <= map_addr);
ASSERT(map_addr + PGUP(map_size) <= addr + PGUP(size));
if (sys_munmap(map_addr, map_size))
rc = -1;
} else {
if (!UnmapViewOfFile(map_addr))
rc = -1;
if (!CloseHandle(map->h))
rc = -1;
}
__maps_lock();
__maps_free(map);
__maps_check();
goto StartOver;
}
map = next;
continue;
} else if (IsWindows()) {
@@ -240,35 +221,34 @@ StartOver:;
size_t right = map_size - left;
ASSERT(right > 0);
ASSERT(left > 0);
map->addr += left;
map->size = right;
if (!(map->flags & MAP_ANONYMOUS))
map->off += left;
__maps.pages -= (left + pagesz - 1) / pagesz;
__maps_check();
if (!untrack_only) {
__maps_unlock();
ASSERT(addr <= map_addr);
ASSERT(map_addr + PGUP(left) <= addr + PGUP(size));
if (sys_munmap(map_addr, left) == -1)
rc = -1;
__maps_lock();
goto StartOver;
struct Map *leftmap;
if ((leftmap = __maps_alloc())) {
map->addr += left;
map->size = right;
if (!(map->flags & MAP_ANONYMOUS))
map->off += left;
__maps.pages -= (left + pagesz - 1) / pagesz;
__maps_check();
leftmap->addr = map_addr;
leftmap->size = left;
dll_make_first(&delete, &leftmap->elem);
} else {
rc = -1;
}
} else if (addr + PGUP(size) >= map_addr + PGUP(map_size)) {
// shave off righthand side of mapping
size_t left = addr - map_addr;
size_t right = map_addr + map_size - addr;
map->size = left;
__maps.pages -= (right + pagesz - 1) / pagesz;
__maps_check();
if (!untrack_only) {
__maps_unlock();
ASSERT(PGUP(right) <= PGUP(size));
if (sys_munmap(addr, right) == -1)
rc = -1;
__maps_lock();
goto StartOver;
struct Map *rightmap;
if ((rightmap = __maps_alloc())) {
map->size = left;
__maps.pages -= (right + pagesz - 1) / pagesz;
__maps_check();
rightmap->addr = addr;
rightmap->size = right;
dll_make_first(&delete, &rightmap->elem);
} else {
rc = -1;
}
} else {
// punch hole in mapping
@@ -277,27 +257,28 @@ StartOver:;
size_t right = map_size - middle - left;
struct Map *leftmap;
if ((leftmap = __maps_alloc())) {
leftmap->next = map;
leftmap->addr = map_addr;
leftmap->size = left;
leftmap->off = map->off;
leftmap->prot = map->prot;
leftmap->flags = map->flags;
map->addr += left + middle;
map->size = right;
if (!(map->flags & MAP_ANONYMOUS))
map->off += left + middle;
dll_make_first(&__maps.used, &leftmap->elem);
*prev = leftmap;
__maps.pages -= (middle + pagesz - 1) / pagesz;
__maps.count += 1;
__maps_check();
if (!untrack_only) {
__maps_unlock();
if (sys_munmap(addr, size) == -1)
rc = -1;
__maps_lock();
goto StartOver;
struct Map *middlemap;
if ((middlemap = __maps_alloc())) {
leftmap->next = map;
leftmap->addr = map_addr;
leftmap->size = left;
leftmap->off = map->off;
leftmap->prot = map->prot;
leftmap->flags = map->flags;
map->addr += left + middle;
map->size = right;
if (!(map->flags & MAP_ANONYMOUS))
map->off += left + middle;
dll_make_first(&__maps.used, &leftmap->elem);
*prev = leftmap;
__maps.pages -= (middle + pagesz - 1) / pagesz;
__maps.count += 1;
__maps_check();
middlemap->addr = addr;
middlemap->size = size;
dll_make_first(&delete, &middlemap->elem);
} else {
rc = -1;
}
} else {
rc = -1;
@@ -309,6 +290,34 @@ StartOver:;
}
__maps_unlock();
// delete mappings
for (struct Dll *e = dll_first(delete); e; e = dll_next(delete, e)) {
map = MAP_CONTAINER(e);
if (!untrack_only) {
if (!IsWindows()) {
if (sys_munmap(map->addr, map->size))
rc = -1;
} else {
if (!UnmapViewOfFile(map->addr))
rc = -1;
if (!CloseHandle(map->h))
rc = -1;
}
}
}
// free mappings
if (!dll_is_empty(delete)) {
__maps_lock();
struct Dll *e;
while ((e = dll_first(delete))) {
dll_remove(&delete, e);
__maps_free(MAP_CONTAINER(e));
}
__maps_check();
__maps_unlock();
}
return rc;
}
+2 -4
View File
@@ -64,11 +64,9 @@ int __reservefd_unlocked(int start) {
int fd, f1, f2;
for (;;) {
f1 = atomic_load_explicit(&g_fds.f, memory_order_acquire);
for (fd = MAX(start, f1); fd < g_fds.n; ++fd) {
if (!g_fds.p[fd].kind) {
for (fd = MAX(start, f1); fd < g_fds.n; ++fd)
if (!g_fds.p[fd].kind)
break;
}
}
fd = __ensurefds_unlocked(fd);
bzero(g_fds.p + fd, sizeof(*g_fds.p));
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
+1 -1
View File
@@ -5,7 +5,7 @@
#define SYSDEBUG 0
#endif
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 1 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _LOCKTRACE 0 /* not configurable w/ flag yet */
-1
View File
@@ -42,4 +42,3 @@
void *malloc(size_t n) {
return dlmalloc(n);
}
+24 -23
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/cxaatexit.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.internal.h"
@@ -30,8 +31,6 @@ struct Dtor {
struct Dtor *next;
};
static _Thread_local struct Dtor *__cxa_thread_atexit_list;
static void _pthread_unwind(struct CosmoTib *tib) {
struct PosixThread *pt;
struct _pthread_cleanup_buffer *cb;
@@ -42,24 +41,24 @@ static void _pthread_unwind(struct CosmoTib *tib) {
}
}
static void __cxa_thread_unkey(struct CosmoTib *tib) {
void *val;
int i, j, gotsome;
pthread_key_dtor dtor;
for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; ++j) {
for (gotsome = i = 0; i < PTHREAD_KEYS_MAX; ++i) {
if ((val = tib->tib_keys[i]) &&
(dtor = atomic_load_explicit(_pthread_key_dtor + i,
memory_order_relaxed)) &&
dtor != (pthread_key_dtor)-1) {
gotsome = 1;
tib->tib_keys[i] = 0;
static void _pthread_unkey(struct CosmoTib *tib) {
for (int j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; ++j) {
bool gotsome = false;
for (int i = 0; i < PTHREAD_KEYS_MAX; ++i) {
void *val;
pthread_key_dtor dtor;
if ((dtor = atomic_load_explicit(&_pthread_key_dtor[i],
memory_order_acquire)) &&
dtor != (pthread_key_dtor)-1 &&
(val = atomic_exchange_explicit(&tib->tib_keys[i], 0,
memory_order_relaxed))) {
STRACE("_pthread_unkey(%t, %p)", dtor, val);
gotsome = true;
dtor(val);
}
}
if (!gotsome) {
if (!gotsome)
break;
}
}
}
@@ -67,9 +66,8 @@ static void _pthread_ungarbage(struct CosmoTib *tib) {
struct Garbages *g;
while ((g = tib->tib_garbages)) {
tib->tib_garbages = 0;
while (g->i--) {
while (g->i--)
((void (*)(intptr_t))g->p[g->i].fn)(g->p[g->i].arg);
}
_weaken(free)(g->p);
_weaken(free)(g);
}
@@ -82,10 +80,11 @@ void __cxa_thread_finalize(void) {
_pthread_unwind(tib);
if (tib->tib_nsync)
_weaken(nsync_waiter_destroy)(tib->tib_nsync);
__cxa_thread_unkey(tib);
_pthread_unkey(tib);
_pthread_ungarbage(tib);
while ((dtor = __cxa_thread_atexit_list)) {
__cxa_thread_atexit_list = dtor->next;
while ((dtor = tib->tib_atexit)) {
STRACE("__cxa_finalize(%t, %p)", dtor->fun, dtor->arg);
tib->tib_atexit = dtor->next;
((void (*)(void *))dtor->fun)(dtor->arg);
_weaken(free)(dtor);
}
@@ -97,9 +96,11 @@ int __cxa_thread_atexit_impl(void *fun, void *arg, void *dso_symbol) {
return -1;
if (!(dtor = _weaken(malloc)(sizeof(struct Dtor))))
return -1;
struct CosmoTib *tib;
tib = __get_tls();
dtor->fun = fun;
dtor->arg = arg;
dtor->next = __cxa_thread_atexit_list;
__cxa_thread_atexit_list = dtor;
dtor->next = tib->tib_atexit;
tib->tib_atexit = dtor;
return 0;
}
+20 -13
View File
@@ -24,6 +24,7 @@
#include "libc/intrin/dll.h"
#include "libc/intrin/getenv.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/nt/files.h"
@@ -37,6 +38,8 @@
#include "libc/stdalign.internal.h"
#include "libc/str/locale.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
@@ -138,24 +141,23 @@ textstartup void __enable_tls(void) {
size_t siz = ROUNDUP(I(_tls_size) + sizeof(struct CosmoTib), TLS_ALIGNMENT);
if (siz <= sizeof(__static_tls)) {
// if tls requirement is small then use the static tls block
// which helps avoid a system call for appes with little tls
// which helps avoid a system call for apes with little tls.
// this is crucial to keeping life.com 16 kilobytes in size!
mem = __static_tls;
} else {
// if this binary needs a hefty tls block then we'll bank on
// malloc() being linked, which links _mapanon(). otherwise
// if you exceed this, you need to __static_yoink("_mapanon").
// please note that it's probably too early to call calloc()
mem = _weaken(_mapanon)(siz);
// if a binary needs this much thread_local storage, then it
// surely must have linked the mmap() function at some point
// we can't call mmap() because it's too early for sig block
mem = _weaken(__mmap)(0, siz, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
struct CosmoTib *tib = (struct CosmoTib *)(mem + siz - sizeof(*tib));
char *tls = mem + siz - sizeof(*tib) - I(_tls_size);
// copy in initialized data section
if (I(_tdata_size)) {
if (I(_tdata_size))
memcpy(tls, _tdata_start, I(_tdata_size));
}
#elif defined(__aarch64__)
@@ -166,9 +168,16 @@ textstartup void __enable_tls(void) {
char *mem;
if (I(_tls_align) <= TLS_ALIGNMENT && size <= sizeof(__static_tls)) {
// if tls requirement is small then use the static tls block
// which helps avoid a system call for apes with little tls.
// this is crucial to keeping life.com 16 kilobytes in size!
mem = __static_tls;
} else {
mem = _weaken(_mapanon)(size);
// if a binary needs this much thread_local storage, then it
// surely must have linked the mmap() function at some point
// we can't call mmap() because it's too early for sig block
mem = _weaken(__mmap)(0, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
struct CosmoTib *tib =
@@ -180,9 +189,8 @@ textstartup void __enable_tls(void) {
size_t dtv_size = sizeof(uintptr_t) * 2;
char *tdata = (char *)dtv + ROUNDUP(dtv_size, I(_tdata_align));
if (I(_tdata_size)) {
if (I(_tdata_size))
memmove(tdata, _tdata_start, I(_tdata_size));
}
// Set the DTV.
//
@@ -247,9 +255,8 @@ textstartup void __enable_tls(void) {
#ifdef __x86_64__
// rewrite the executable tls opcodes in memory
if (IsWindows() || IsOpenbsd() || IsNetbsd()) {
if (IsWindows() || IsOpenbsd() || IsNetbsd())
__morph_tls();
}
#endif
// we are now allowed to use tls
+1 -1
View File
@@ -58,7 +58,7 @@ static struct ZiposHandle *__zipos_alloc(struct Zipos *zipos, size_t size) {
granularity = __granularity();
mapsize = sizeof(struct ZiposHandle) + size;
mapsize = (mapsize + granularity - 1) & -granularity;
if ((h = __mmap(randaddr(), mapsize, PROT_READ | PROT_WRITE,
if ((h = __mmap(0, mapsize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
h->size = size;
h->zipos = zipos;
+3 -2
View File
@@ -54,9 +54,8 @@ long _pthread_cancel_ack(void) {
pthread_exit(PTHREAD_CANCELED);
}
pt->pt_flags |= PT_NOCANCEL;
if (IsOpenbsd()) {
if (IsOpenbsd())
pt->pt_flags |= PT_OPENBSD_KLUDGE;
}
return ecanceled();
}
@@ -351,6 +350,7 @@ static errno_t _pthread_cancel_everyone(void) {
* @param thread may be 0 to cancel all threads except self
* @return 0 on success, or errno on error
* @raise ESRCH if system thread wasn't alive or we lost a race
* @cancelationpoint
*/
errno_t pthread_cancel(pthread_t thread) {
struct PosixThread *arg;
@@ -401,6 +401,7 @@ void pthread_testcancel(void) {
*
* @return 0 if not cancelled or cancelation is blocked or `ECANCELED`
* in masked mode when the calling thread has been cancelled
* @cancelationpoint
*/
errno_t pthread_testcancel_np(void) {
struct PosixThread *pt;
+1
View File
@@ -117,6 +117,7 @@ static int PosixThread(void *arg, int tid) {
}
// set long jump handler so pthread_exit can bring control back here
if (!setjmp(pt->pt_exiter)) {
sigdelset(&pt->pt_attr.__sigmask, SIGTHR);
if (IsWindows()) {
atomic_store_explicit(&__get_tls()->tib_sigmask, pt->pt_attr.__sigmask,
memory_order_release);
@@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ 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 │
@@ -16,24 +16,22 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/pr.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
const char *DescribePrctlOperation(int x) {
switch (x) {
case PR_GET_NAME:
return "PR_GET_NAME";
case PR_SET_NO_NEW_PRIVS:
return "PR_SET_NO_NEW_PRIVS";
case PR_SET_SECCOMP:
return "PR_SET_SECCOMP";
case PR_GET_SECCOMP:
return "PR_GET_SECCOMP";
case PR_CAPBSET_READ:
return "PR_CAPBSET_READ";
case PR_CAPBSET_DROP:
return "PR_CAPBSET_DROP";
default:
return "PRCTL_???";
}
/**
* Garbage collects POSIX threads runtime.
*
* Let's say you want to run a memory leak detector. You can say:
*
* while (!pthread_orphan_np())
* pthread_decimate_np();
*
* To wait until all threads have exited.
*
* @return 0 on success, or errno on error
*/
int pthread_decimate_np(void) {
_pthread_decimate();
return 0;
}
+3 -3
View File
@@ -48,9 +48,9 @@ int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
if (!dtor)
dtor = (pthread_key_dtor)-1;
for (i = 0; i < PTHREAD_KEYS_MAX; ++i) {
if (!(expect = atomic_load_explicit(_pthread_key_dtor + i,
memory_order_acquire)) &&
atomic_compare_exchange_strong_explicit(_pthread_key_dtor + i, &expect,
if (!(expect = atomic_load_explicit(&_pthread_key_dtor[i],
memory_order_relaxed)) &&
atomic_compare_exchange_strong_explicit(&_pthread_key_dtor[i], &expect,
dtor, memory_order_release,
memory_order_relaxed)) {
*key = i;
+5 -4
View File
@@ -16,7 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/thread/posixthread.internal.h"
@@ -32,10 +31,12 @@
*
* @param key was created by pthread_key_create()
* @return 0 on success, or errno on error
* @raise EINVAL if `key` is invalid
*/
int pthread_key_delete(pthread_key_t k) {
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
atomic_store_explicit(_pthread_key_dtor + k, 0, memory_order_release);
if (!(0 <= k && k < PTHREAD_KEYS_MAX))
return EINVAL; // corrupt key identifier
if (!atomic_exchange_explicit(&_pthread_key_dtor[k], 0, memory_order_acq_rel))
return EINVAL; // delete called twice
return 0;
}
+2 -1
View File
@@ -1,7 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_THREAD_H_
#define COSMOPOLITAN_LIBC_THREAD_THREAD_H_
#define PTHREAD_KEYS_MAX 48
#define PTHREAD_KEYS_MAX 46
#define PTHREAD_STACK_MIN 65536
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
@@ -166,6 +166,7 @@ int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int) libcesque paramsnon
int pthread_mutexattr_settype(pthread_mutexattr_t *, int) libcesque paramsnonnull();
int pthread_once(pthread_once_t *, void (*)(void)) paramsnonnull();
int pthread_orphan_np(void) libcesque;
int pthread_decimate_np(void) libcesque;
int pthread_rwlock_destroy(pthread_rwlock_t *) libcesque paramsnonnull();
int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *) libcesque paramsnonnull((1));
int pthread_rwlock_rdlock(pthread_rwlock_t *) libcesque paramsnonnull();
+2 -1
View File
@@ -39,7 +39,8 @@ struct CosmoTib {
uint32_t tib_sigstack_flags;
_Atomic(int) tib_relock_maps;
void *tib_nsync;
void *tib_keys[47];
void *tib_atexit;
_Atomic(void *) tib_keys[46];
} __attribute__((__aligned__(64)));
extern int __threaded;
+3 -1
View File
@@ -14,9 +14,11 @@ TEST_CTL_TESTS = $(TEST_CTL_COMS:%=%.ok)
TEST_CTL_DIRECTDEPS = \
CTL \
LIBC_CALLS \
LIBC_STDIO \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_STDIO \
LIBC_THREAD \
THIRD_PARTY_LIBCXX \
+3 -3
View File
@@ -20,9 +20,9 @@
#include "ctl/array.h"
#include "libc/mem/leaks.h"
#include <algorithm>
#include <array>
#define ctl std
// #include <algorithm>
// #include <array>
// #define ctl std
int
main()
+2 -4
View File
@@ -35,10 +35,9 @@ main()
// Test basic copy
ctl::copy(src.begin(), src.end(), dest.begin());
for (size_t i = 0; i < 5; ++i) {
for (size_t i = 0; i < 5; ++i)
if (dest[i] != src[i])
return 1;
}
// Test partial copy
ctl::array<int, 5> dest2 = { 0, 0, 0, 0, 0 };
@@ -57,10 +56,9 @@ main()
// Test copy with empty range
ctl::array<int, 5> dest4 = { 0, 0, 0, 0, 0 };
ctl::copy(src.begin(), src.begin(), dest4.begin());
for (size_t i = 0; i < 5; ++i) {
for (size_t i = 0; i < 5; ++i)
if (dest4[i] != 0)
return 4;
}
// Test copy return value
ctl::array<int, 5> dest5 = { 0, 0, 0, 0, 0 };
+102
View File
@@ -0,0 +1,102 @@
// -*- 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 "ctl/is_base_of.h"
// #include <type_traits>
// #define ctl std
// Test classes
class A
{};
class B : public A
{};
class C : public B
{};
class D
{};
struct Empty
{};
template<typename T>
class TemplateClass
{};
class VirtualBase
{};
class VirtualDerived : virtual public VirtualBase
{};
int
main()
{
// Test basic inheritance
if (!ctl::is_base_of_v<A, B>)
return 1;
if (!ctl::is_base_of_v<A, C>)
return 2;
if (ctl::is_base_of_v<B, A>)
return 3;
if (ctl::is_base_of_v<C, A>)
return 4;
if (ctl::is_base_of_v<A, D>)
return 5;
// Test with same type
if (!ctl::is_base_of_v<A, A>)
return 6;
if (!ctl::is_base_of_v<B, B>)
return 7;
// Test with void
if (ctl::is_base_of_v<void, void>)
return 8;
if (ctl::is_base_of_v<A, void>)
return 9;
if (ctl::is_base_of_v<void, A>)
return 10;
// Test with fundamental types
if (ctl::is_base_of_v<int, int>)
return 11;
if (ctl::is_base_of_v<int, double>)
return 12;
if (ctl::is_base_of_v<double, int>)
return 13;
// Test with empty class
if (ctl::is_base_of_v<Empty, A>)
return 14;
if (ctl::is_base_of_v<A, Empty>)
return 15;
// Test with template class
if (ctl::is_base_of_v<TemplateClass<int>, A>)
return 16;
if (ctl::is_base_of_v<A, TemplateClass<int>>)
return 17;
// Test with virtual inheritance
if (!ctl::is_base_of_v<VirtualBase, VirtualDerived>)
return 18;
if (ctl::is_base_of_v<VirtualDerived, VirtualBase>)
return 19;
return 0; // All tests passed
}
+163
View File
@@ -0,0 +1,163 @@
// -*- 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 "ctl/istringstream.h"
#include "libc/mem/leaks.h"
// #include <sstream>
// #define ctl std
int
main()
{
// Test default constructor
{
ctl::istringstream iss;
if (iss.eof())
return 1;
if (!iss.good())
return 1;
}
// Test constructor with initial string
{
ctl::istringstream iss("Hello, world!");
if (iss.str() != "Hello, world!")
return 2;
}
// Test reading a char
{
ctl::istringstream iss("A");
char c;
iss >> c;
if (c != 'A' || !iss.good())
return 3;
}
// Test reading a string
{
ctl::istringstream iss("Hello World");
ctl::string s;
iss >> s;
if (s != "Hello" || !iss.good())
return 4;
}
// Test reading multiple strings
{
ctl::istringstream iss("One Two Three");
ctl::string s1, s2, s3;
iss >> s1 >> s2 >> s3;
if (s1 != "One" || s2 != "Two" || s3 != "Three" || iss.good() ||
!iss.eof())
return 5;
}
// Test reading integers
{
ctl::istringstream iss("123 -456 789");
int a, b, c;
iss >> a >> b >> c;
if (a != 123 || b != -456 || c != 789 || iss.good() || !iss.eof())
return 6;
}
// Test reading floating-point numbers
{
ctl::istringstream iss("3.14 -2.718");
float f;
double d;
iss >> f >> d;
if (f != 3.14f || d != -2.718 || iss.good() || !iss.eof())
return 7;
}
// Test reading past the end of the stream
{
ctl::istringstream iss("42");
int n;
iss >> n;
if (n != 42 || iss.good() || !iss.eof())
return 8;
iss >> n;
if (iss.good())
return 9;
if (!iss.eof())
return 10;
}
// Test reading invalid data
{
ctl::istringstream iss("not_a_number");
int n;
iss >> n;
if (iss.good() || !iss.fail())
return 11;
}
// Test str() setter
{
ctl::istringstream iss;
iss.str("New content");
if (iss.str() != "New content" || !iss.good())
return 12;
}
// Test reading after setting a new string
{
ctl::istringstream iss("Old content");
iss.str("New content");
ctl::string s;
iss >> s;
if (s != "New" || !iss.good())
return 13;
}
// Test reading a mixture of types
{
ctl::istringstream iss("42 3.14 Hello");
int i;
double d;
ctl::string s;
iss >> i >> d >> s;
if (i != 42 || d != 3.14 || s != "Hello" || iss.good() || !iss.eof())
return 14;
}
// Test reading with leading whitespace
{
ctl::istringstream iss(" 42");
int n;
iss >> n;
if (n != 42 || iss.good() || !iss.eof())
return 15;
}
// Test clear() only affects error state, not content
{
ctl::istringstream iss("Test");
iss.setstate(ctl::ios_base::failbit);
iss.clear();
if (!iss.good() || iss.str() != "Test")
return 16;
}
CheckForMemoryLeaks();
}
+140
View File
@@ -0,0 +1,140 @@
// -*- 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 "ctl/ostringstream.h"
#include "libc/mem/leaks.h"
// #include <sstream>
// #define ctl std
int
main()
{
// Test default constructor and basic string insertion
{
ctl::ostringstream oss;
oss << "Hello, world!";
if (oss.str() != "Hello, world!")
return 1;
}
// Test constructor with initial string (overwrite mode)
{
ctl::ostringstream oss("Initial content");
oss << "New";
if (oss.str() != "Newtial content")
return 2;
}
// Test overwrite and append behavior
{
ctl::ostringstream oss("Hello, world!");
oss << "Hi";
if (oss.str() != "Hillo, world!")
return 3;
oss << " Earth";
if (oss.str() != "Hi Earthorld!")
return 4;
}
// Test multiple insertions of different types
{
ctl::ostringstream oss;
oss << "Int: " << 42 << ", Float: " << 3.14f << ", Double: " << 2.718;
if (oss.str() != "Int: 42, Float: 3.14, Double: 2.718")
return 5;
}
// Test char insertion
{
ctl::ostringstream oss("ABCDEF");
oss << 'X' << 'Y' << 'Z';
if (oss.str() != "XYZDEF")
return 6;
}
// Test unsigned types
{
ctl::ostringstream oss("Numbers: ");
unsigned int ui = 12345;
unsigned long ul = 67890UL;
oss << ui << " " << ul;
if (oss.str() != "12345 67890")
return 7;
}
// Test long type
{
ctl::ostringstream oss("Long: ");
long l = -9876543210L;
oss << l;
if (oss.str() != "-9876543210")
return 8;
}
// Test clear() method
{
ctl::ostringstream oss("not that kind of clear");
oss.clear();
if (!oss.good() || oss.str() != "not that kind of clear")
return 9;
}
// Test str() setter method
{
ctl::ostringstream oss;
oss.str("New content");
oss << "Old";
if (oss.str() != "Old content")
return 10;
}
// Test chaining of insertion operators
{
ctl::ostringstream oss("Start: ");
oss << "Chain " << 1 << " " << 2.0 << " " << 'Z';
if (oss.str() != "Chain 1 2 Z")
return 11;
}
// Test insertion when stream is not in good state
{
ctl::ostringstream oss("Original");
oss.setstate(ctl::ios_base::failbit);
oss << "This should not be inserted";
if (oss.str() != "Original")
return 12;
}
// Test with larger amounts of data
{
ctl::ostringstream oss("Prefix: ");
for (int i = 0; i < 1000; ++i) {
oss << "Line " << i << "\n";
}
ctl::string result = oss.str();
if (result.substr(0, 14) != "Line 0\nLine 1\n")
return 13;
if (result.substr(result.length() - 8) != "ine 999\n")
return 14;
}
CheckForMemoryLeaks();
return 0;
}
+126
View File
@@ -0,0 +1,126 @@
// -*- 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 "ctl/string.h"
#include "libc/limits.h"
#include "libc/math.h"
#include "libc/mem/leaks.h"
int
main()
{
// test integer conversion
{
if (ctl::to_string(0) != "0")
return 1;
if (ctl::to_string(3) != "3")
return 1;
if (ctl::to_string(INT32_MAX) != "2147483647")
return 2;
if (ctl::to_string(INT32_MIN) != "-2147483648")
return 3;
if (ctl::to_string(UINT32_MAX) != "4294967295")
return 4;
if (ctl::to_string(INT64_MAX) != "9223372036854775807")
return 5;
if (ctl::to_string(INT64_MIN) != "-9223372036854775808")
return 6;
if (ctl::to_string(UINT64_MAX) != "18446744073709551615")
return 7;
}
// test float conversion
// we diverge from std::to_string(float) because it's garbage
{
if (ctl::to_string(0.f) != "0") // 0.000000
return 8;
if (ctl::to_string(-0.f) != "-0") // 0.000000
return 9;
if (ctl::to_string(3.f) != "3") // 3.000000
return 10;
if (ctl::to_string(3.14f) != "3.14") // 3.140000
return 11;
if (ctl::to_string(3.140001f) != "3.140001")
return 12;
if (ctl::to_string(1000000000.f) != "1000000000") // 1000000000.000000
return 12;
if (ctl::to_string(10000000000.f) != "1e+10") // 10000000000.000000
return 12;
if (ctl::to_string(NAN) != "nan")
return 13;
if (ctl::to_string(INFINITY) != "inf")
return 14;
if (ctl::to_string(-INFINITY) != "-inf")
return 15;
if (ctl::to_string(FLT_MIN) != "1.1754944e-38") // 0.000000 lool
return 16;
if (ctl::to_string(-FLT_MIN) != "-1.1754944e-38")
return 17;
if (ctl::to_string(FLT_MAX) != "3.4028235e+38")
return 18;
if (ctl::to_string(-FLT_MAX) != "-3.4028235e+38")
return 19;
}
// test double conversion
{
if (ctl::to_string(0.) != "0")
return 20;
if (ctl::to_string(-0.) != "-0")
return 21;
if (ctl::to_string(3.) != "3")
return 22;
if (ctl::to_string(2147483647.) != "2147483647")
return 23;
if (ctl::to_string(-2147483648.) != "-2147483648")
return 23;
if (ctl::to_string(10000000000.) != "1e+10")
return 23;
if (ctl::to_string(3.14) != "3.14")
return 23;
if (ctl::to_string(3.140001) != "3.140001")
return 24;
if (ctl::to_string(DBL_MIN) != "2.2250738585072014e-308")
return 25;
if (ctl::to_string(-DBL_MIN) != "-2.2250738585072014e-308")
return 26;
if (ctl::to_string(DBL_MAX) != "1.7976931348623157e+308")
return 27;
if (ctl::to_string(-DBL_MAX) != "-1.7976931348623157e+308")
return 28;
}
// test long double conversion
{
if (ctl::to_string(0.L) != "0")
return 29;
if (ctl::to_string(-0.L) != "-0")
return 30;
if (ctl::to_string(3.L) != "3")
return 31;
if (ctl::to_string(3.14L) != "3.14")
return 32;
if (ctl::to_string(LDBL_MAX) != "1.189731495357232e+4932")
return 33;
if (ctl::to_string(-LDBL_MAX) != "-1.189731495357232e+4932")
return 34;
}
CheckForMemoryLeaks();
}
+99
View File
@@ -24,6 +24,46 @@
// #include <vector>
// #define ctl std
static int counter;
// Test with non-trivial type
struct NonTrivial
{
int value;
NonTrivial(int v) : value(v)
{
++counter;
}
NonTrivial(const NonTrivial& other) : value(other.value)
{
++counter;
}
NonTrivial(NonTrivial&& other) noexcept : value(other.value)
{
++counter;
}
~NonTrivial()
{
--counter;
}
NonTrivial& operator=(const NonTrivial& other)
{
value = other.value;
return *this;
}
NonTrivial& operator=(NonTrivial&& other) noexcept
{
value = other.value;
return *this;
}
};
int
main()
{
@@ -352,5 +392,64 @@ main()
return 80;
}
{
ctl::vector<int> dog(8, 0);
if (dog.size() != 8)
return 81;
if (dog[0] != 0)
return 82;
}
// Test erase(const_iterator first, const_iterator last)
{
ctl::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Test erasing from the middle
auto it = v.erase(v.begin() + 3, v.begin() + 7);
if (v.size() != 6 || v != ctl::vector<int>{ 1, 2, 3, 8, 9, 10 } ||
it != v.begin() + 3)
return 83;
// Test erasing from the beginning
it = v.erase(v.begin(), v.begin() + 2);
if (v.size() != 4 || v != ctl::vector<int>{ 3, 8, 9, 10 } ||
it != v.begin())
return 84;
// Test erasing to the end
it = v.erase(v.begin() + 2, v.end());
if (v.size() != 2 || v != ctl::vector<int>{ 3, 8 } || it != v.end())
return 85;
// Test erasing all elements
it = v.erase(v.begin(), v.end());
if (!v.empty() || it != v.end())
return 86;
// Test erasing empty range
v = { 1, 2, 3, 4, 5 };
it = v.erase(v.begin() + 2, v.begin() + 2);
if (v.size() != 5 || v != ctl::vector<int>{ 1, 2, 3, 4, 5 } ||
it != v.begin() + 2)
return 87;
counter = 0;
{
ctl::vector<NonTrivial> v2;
for (int i = 0; i < 10; ++i)
v2.emplace_back(i);
v2.erase(v2.begin() + 3, v2.begin() + 7);
if (v2.size() != 6 || counter != 6)
return 89;
for (int i = 0; i < (int)v2.size(); ++i)
if (v2[i].value != (i < 3 ? i : i + 4))
return 90;
}
if (counter != 0)
return 91;
}
CheckForMemoryLeaks();
}
@@ -16,10 +16,19 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
void *randaddr(void) {
static unsigned long lcg = 1;
lcg *= 6364136223846793005;
lcg += 1442695040888963407;
return (void *)(lcg >> 48 << 28);
void *wut(void *arg) {
pthread_id_np_t tid;
pthread_getunique_np(pthread_self(), &tid);
ASSERT_EQ(gettid(), tid);
return 0;
}
TEST(pthread_getunique_np, test) {
pthread_t id;
ASSERT_EQ(0, pthread_create(&id, 0, wut, (void *)1));
ASSERT_EQ(0, pthread_join(id, 0));
}
+25
View File
@@ -0,0 +1,25 @@
-- 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.
for _ = 1, 1000 do
local uuid = UuidV7()
assert(#uuid == 36)
assert(string.sub(uuid, 9, 9) == "-")
assert(string.sub(uuid, 14, 14) == "-")
assert(string.sub(uuid, 15, 15) == "7")
assert(string.sub(uuid, 19, 19) == "-")
local y = string.sub(uuid, 20, 20)
assert(y == "8" or y == "9" or y == "a" or y == "b")
assert(string.sub(uuid, 24, 24) == "-")
end
+1
View File
@@ -427,6 +427,7 @@ is_bourne_compatible_shell (const char *path)
"sh",
"bash",
"dash",
"cocmd",
"ksh",
"rksh",
"zsh",
-177
View File
@@ -1,177 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 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 "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/append.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "tool/build/lib/getargs.h"
#include "tool/build/lib/interner.h"
#define LOOKINGAT(p, pe, s) LookingAt(p, pe, s, strlen(s))
struct Visited {
size_t i, n;
const char **p;
};
char *output;
const char *prog;
struct Interner *visited;
void Visit(const char *);
static wontreturn void Die(const char *reason) {
tinyprint(2, prog, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void DieSys(const char *thing) {
perror(thing);
exit(1);
}
static wontreturn void DieOom(void) {
Die("out of memory");
}
static void Appends(char **b, const char *s) {
if (appends(b, s) == -1)
DieOom();
}
static void Appendd(char **b, const void *p, size_t n) {
if (appendd(b, p, n) == -1)
DieOom();
}
size_t GetFdSize(int fd) {
struct stat st;
if (fstat(fd, &st)) {
DieSys("fstat");
}
return st.st_size;
}
bool LookingAt(const char *p, const char *pe, const char *s, size_t n) {
return pe - p >= n && memcmp(p, s, n) == 0;
}
void Process(const char *p, const char *pe, const char *path, bool isheader) {
int level;
bool noformat;
const char *p2, *dq, *name;
for (noformat = false, level = 0; p < pe; p = p2) {
p2 = memchr(p, '\n', pe - p);
p2 = p2 ? p2 + 1 : pe;
if (LOOKINGAT(p, pe, "#if")) {
if (isheader && !level++)
continue;
}
if (LOOKINGAT(p, pe, "#endif")) {
if (isheader && !--level)
continue;
}
if (LOOKINGAT(p, pe, "/* clang-format off */")) {
noformat = true;
} else if (LOOKINGAT(p, pe, "/* clang-format on */")) {
noformat = false;
}
if (LOOKINGAT(p, pe, "#include \"")) {
name = p + strlen("#include \"");
dq = memchr(name, '"', pe - name);
if (dq) {
Visit(strndup(name, dq - name));
continue;
}
}
Appendd(&output, p, p2 - p);
}
if (noformat) {
Appends(&output, "/* clang-format on */\n");
}
}
void Visit(const char *path) {
int fd;
char *map;
size_t size;
bool isheader;
if (!endswith(path, ".h") && !endswith(path, ".inc"))
return;
if (endswith(path, ".internal.h"))
return;
if (endswith(path, "/internal.h"))
return;
if (endswith(path, ".internal.inc"))
return;
if (endswith(path, "/internal.inc"))
return;
if (startswith(path, "libc/isystem/"))
return;
isheader = endswith(path, ".h");
if (isheader && isinterned(visited, path))
return;
Appends(&output, "\n\f\n/*!BEGIN ");
Appends(&output, path);
Appends(&output, " */\n\n");
intern(visited, path);
if ((fd = open(path, O_RDONLY)) == -1)
DieSys(path);
if ((size = GetFdSize(fd))) {
map = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED)
DieSys(path);
Process(map, map + size, path, isheader);
if (munmap(map, size))
DieSys(path);
}
if (close(fd))
DieSys(path);
}
int main(int argc, char *argv[]) {
size_t bytes;
const char *src;
struct GetArgs ga;
prog = argv[0];
if (!prog)
prog = "rollup";
visited = newinterner();
Appends(&output, "#ifndef COSMOPOLITAN_H_\n");
Appends(&output, "#define COSMOPOLITAN_H_\n");
getargs_init(&ga, argv + 1);
while ((src = getargs_next(&ga))) {
Visit(src);
}
getargs_destroy(&ga);
Appends(&output, "\n");
Appends(&output, "#endif /* COSMOPOLITAN_H_ */\n");
bytes = appendz(output).i;
if (write(1, output, bytes) != bytes) {
DieSys(prog);
}
freeinterner(visited);
return 0;
}
+36 -3
View File
@@ -44,6 +44,19 @@ make -j64 m=$AMD64 \
o/$AMD64/tool/build/zipobj.dbg \
o/$AMD64/tool/build/apelink.dbg \
o/$AMD64/tool/build/pecheck.dbg \
o/$AMD64/tool/build/ar.dbg \
o/$AMD64/tool/build/chmod.dbg \
o/$AMD64/tool/build/cocmd.dbg \
o/$AMD64/tool/build/compile.dbg \
o/$AMD64/tool/build/cp.dbg \
o/$AMD64/tool/build/echo.dbg \
o/$AMD64/tool/build/gzip.dbg \
o/$AMD64/tool/build/objbincopy.dbg \
o/$AMD64/tool/build/package.dbg \
o/$AMD64/tool/build/rm.dbg \
o/$AMD64/tool/build/touch.dbg \
o/$AMD64/tool/build/sha256sum.dbg \
o/$AMD64/tool/build/resymbol.dbg \
o/$AMD64/third_party/make/make.dbg \
o/$AMD64/third_party/ctags/ctags.dbg
@@ -64,6 +77,19 @@ make -j64 m=$ARM64 \
o/$ARM64/tool/build/zipobj.dbg \
o/$ARM64/tool/build/apelink.dbg \
o/$ARM64/tool/build/pecheck.dbg \
o/$ARM64/tool/build/ar.dbg \
o/$ARM64/tool/build/chmod.dbg \
o/$ARM64/tool/build/cocmd.dbg \
o/$ARM64/tool/build/compile.dbg \
o/$ARM64/tool/build/cp.dbg \
o/$ARM64/tool/build/echo.dbg \
o/$ARM64/tool/build/gzip.dbg \
o/$ARM64/tool/build/objbincopy.dbg \
o/$ARM64/tool/build/package.dbg \
o/$ARM64/tool/build/rm.dbg \
o/$ARM64/tool/build/touch.dbg \
o/$ARM64/tool/build/sha256sum.dbg \
o/$ARM64/tool/build/resymbol.dbg \
o/$ARM64/third_party/make/make.dbg \
o/$ARM64/third_party/ctags/ctags.dbg
@@ -90,10 +116,10 @@ fetch() {
OLD=$PWD
cd "$OUTDIR/"
if [ ! -x bin/x86_64-linux-cosmo-gcc ]; then
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.44/aarch64-gcc.zip
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.45/aarch64-gcc.zip
unzip aarch64-gcc.zip
rm -f aarch64-gcc.zip
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.44/x86_64-gcc.zip
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.45/x86_64-gcc.zip
unzip x86_64-gcc.zip
rm -f x86_64-gcc.zip
fi
@@ -146,7 +172,9 @@ cp -af tool/cosmocc/bin/* "$OUTDIR/bin/"
cp -f o/$AMD64/ape/ape.elf "$OUTDIR/bin/ape-x86_64.elf"
cp -f o/$AMD64/ape/ape.macho "$OUTDIR/bin/ape-x86_64.macho"
cp -f o/$ARM64/ape/ape.elf "$OUTDIR/bin/ape-aarch64.elf"
for x in assimilate march-native mktemper fixupobj zipcopy apelink pecheck mkdeps zipobj; do
for x in assimilate march-native mktemper fixupobj zipcopy apelink pecheck mkdeps zipobj \
ar chmod cocmd cp echo gzip objbincopy package rm touch sha256sum resymbol; do
ape $APELINK \
-l o/$AMD64/ape/ape.elf \
-l o/$ARM64/ape/ape.elf \
@@ -155,6 +183,11 @@ for x in assimilate march-native mktemper fixupobj zipcopy apelink pecheck mkdep
o/$AMD64/tool/build/$x.dbg \
o/$ARM64/tool/build/$x.dbg
done
for x in ar chmod cp echo gzip package rm touch sha256sum; do
mv "$OUTDIR/bin/$x" "$OUTDIR/bin/$x.ape"
done
for x in make ctags; do
ape $APELINK \
-l o/$AMD64/ape/ape.elf \
+4
View File
@@ -1981,6 +1981,10 @@ function Underlong(str) end
--- @return string
function UuidV4() end
--- Generate a uuid_v7
--- @return string
function UuidV7() end
---@param x integer
---@return integer # position of first bit set.
--- Passing `0` will raise an error. Same as the Intel x86 instruction BSF.
+4 -1
View File
@@ -1063,7 +1063,10 @@ FUNCTIONS
This function is not available in unsecure mode.
UuidV4() -> str
Returns an uuid v4 string.
Returns a uuid v4 string.
UuidV7() -> str
Returns a uuid v7 string.
Fetch(url:str[,body:str|{method=value:str,body=value:str,headers=table,...}])
├─→ status:int, {header:str=value:str,...}, body:str
+68
View File
@@ -858,6 +858,74 @@ int LuaUuidV4(lua_State *L) {
return 1;
}
int LuaUuidV7(lua_State *L) {
//See https://www.rfc-editor.org/rfc/rfc9562.html
char bin[16], uuid_str[37];
struct timespec ts = timespec_real();
uint64_t unix_ts_ms = (uint64_t)((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000));
int fractional_ms = (int)floor((double)((double)(ts.tv_nsec - (ts.tv_nsec / 1000000) * 1000000)/1000000) * 4096) <<4;
uint64_t rand_b = _rand64();
int rand_a = fractional_ms | (rand_b & 0x000000000000000f); //use the last 4 bits of rand_b
bin[0] = unix_ts_ms >> 050;
bin[1] = unix_ts_ms >> 040;
bin[2] = unix_ts_ms >> 030;
bin[3] = unix_ts_ms >> 020;
bin[4] = unix_ts_ms >> 010;
bin[5] = unix_ts_ms >> 000;
bin[6] = rand_a >> 010;
bin[7] = rand_a >> 000;
bin[8] = rand_b >> 070;
bin[9] = rand_b >> 060;
bin[10] = rand_b >> 050;
bin[11] = rand_b >> 040;
bin[12] = rand_b >> 030;
bin[13] = rand_b >> 020;
bin[14] = rand_b >> 010;
bin[15] = rand_b >> 000;
uuid_str[0] = "0123456789abcdef"[(bin[0] & 0xf0) >>4];
uuid_str[1] = "0123456789abcdef"[(bin[0] & 0x0f)];
uuid_str[2] = "0123456789abcdef"[(bin[1] & 0xf0) >>4];
uuid_str[3] = "0123456789abcdef"[(bin[1] & 0x0f)];
uuid_str[4] = "0123456789abcdef"[(bin[2] & 0xf0) >>4];
uuid_str[5] = "0123456789abcdef"[(bin[2] & 0x0f)];
uuid_str[6] = "0123456789abcdef"[(bin[3] & 0xf0) >>4];
uuid_str[7] = "0123456789abcdef"[(bin[3] & 0x0f)];
uuid_str[8] = '-';
uuid_str[9] = "0123456789abcdef"[(bin[4] & 0xf0) >>4];
uuid_str[10] = "0123456789abcdef"[(bin[4] & 0x0f)];
uuid_str[11] = "0123456789abcdef"[(bin[5] & 0xf0) >>4];
uuid_str[12] = "0123456789abcdef"[(bin[5] & 0x0f)];
uuid_str[13] = '-';
uuid_str[14] = '7';
uuid_str[15] = "0123456789abcdef"[(bin[6] & 0xf0) >>4];
uuid_str[16] = "0123456789abcdef"[(bin[6] & 0x0f)];
uuid_str[17] = "0123456789abcdef"[(bin[7] & 0xf0) >>4];
uuid_str[18] = '-';
uuid_str[19] = "0123456789abcdef"[(0x8 | ((bin[7] & 0x0f) >>2))];
uuid_str[20] = "0123456789abcdef"[(bin[7] & 0x03) | (bin[8] & 0xf0) >>6]; //See https://www.rfc-editor.org/rfc/rfc9562.html#version_field
uuid_str[21] = "0123456789abcdef"[(bin[8] & 0x0f)];
uuid_str[22] = "0123456789abcdef"[(bin[9] & 0xf0) >>4];
uuid_str[23] = '-';
uuid_str[24] = "0123456789abcdef"[(bin[9] & 0x0f)];
uuid_str[25] = "0123456789abcdef"[(bin[10] & 0xf0) >>4];
uuid_str[26] = "0123456789abcdef"[(bin[10] & 0x0f)];
uuid_str[27] = "0123456789abcdef"[(bin[11] & 0xf0) >>4];
uuid_str[28] = "0123456789abcdef"[(bin[11] & 0x0f)];
uuid_str[29] = "0123456789abcdef"[(bin[12] & 0xf0) >>4];
uuid_str[30] = "0123456789abcdef"[(bin[12] & 0x0f)];
uuid_str[31] = "0123456789abcdef"[(bin[13] & 0xf0) >>4];
uuid_str[32] = "0123456789abcdef"[(bin[13] & 0x0f)];
uuid_str[33] = "0123456789abcdef"[(bin[14] & 0xf0) >>4];
uuid_str[34] = "0123456789abcdef"[(bin[14] & 0x0f)];
uuid_str[35] = "0123456789abcdef"[(bin[15] & 0xf0) >>4];
uuid_str[36] = '\0';
lua_pushfstring(L, uuid_str);
return 1;
}
static dontinline int LuaHasherImpl(lua_State *L, size_t k,
int H(const void *, size_t, uint8_t *)) {
size_t n;
+1
View File
@@ -91,6 +91,7 @@ int LuaSlurp(lua_State *);
int LuaUncompress(lua_State *);
int LuaUnderlong(lua_State *);
int LuaUuidV4(lua_State *);
int LuaUuidV7(lua_State *);
int LuaVisualizeControlCodes(lua_State *);
void LuaPushUrlView(lua_State *, struct UrlView *);
+1
View File
@@ -5364,6 +5364,7 @@ static const luaL_Reg kLuaFuncs[] = {
{"Uncompress", LuaUncompress}, //
{"Underlong", LuaUnderlong}, //
{"UuidV4", LuaUuidV4}, //
{"UuidV7", LuaUuidV7}, //
{"VisualizeControlCodes", LuaVisualizeControlCodes}, //
{"Write", LuaWrite}, //
{"bin", LuaBin}, //