mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-10 10:41:27 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70f77aad33 | ||
|
|
d0cd719375 | ||
|
|
61370983e1 | ||
|
|
72511ff0ac | ||
|
|
c1f8d0678c | ||
|
|
e627bfa359 | ||
|
|
acbabedf27 | ||
|
|
239f8ce76e | ||
|
|
ca4cf67eb8 | ||
|
|
78d3b86ec7 | ||
|
|
44191b3f50 | ||
|
|
e437bed006 | ||
|
|
76957983cf | ||
|
|
387310c659 | ||
|
|
4cb5e21ba8 | ||
|
|
1bf2d8e308 | ||
|
|
98e684622b |
No files matched your search
@@ -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
@@ -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.
@@ -18,7 +18,13 @@ CTL_A_CHECKS = \
|
||||
CTL_A_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
THIRD_PARTY_LIBUNWIND \
|
||||
|
||||
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
|
||||
+20
-24
@@ -11,59 +11,55 @@ struct allocator_traits
|
||||
{
|
||||
using allocator_type = Alloc;
|
||||
using value_type = typename Alloc::value_type;
|
||||
using pointer = typename Alloc::pointer;
|
||||
using const_pointer = typename Alloc::const_pointer;
|
||||
using pointer = typename Alloc::value_type*;
|
||||
using const_pointer = const typename Alloc::value_type*;
|
||||
using void_pointer = void*;
|
||||
using const_void_pointer = const void*;
|
||||
using difference_type = typename Alloc::difference_type;
|
||||
using size_type = typename Alloc::size_type;
|
||||
using difference_type = ptrdiff_t;
|
||||
using size_type = size_t;
|
||||
|
||||
using propagate_on_container_copy_assignment = false_type;
|
||||
using propagate_on_container_move_assignment = true_type;
|
||||
using propagate_on_container_swap = false_type;
|
||||
using is_always_equal = true_type;
|
||||
using propagate_on_container_copy_assignment = ctl::false_type;
|
||||
using propagate_on_container_move_assignment = ctl::true_type;
|
||||
using propagate_on_container_swap = ctl::false_type;
|
||||
using is_always_equal = ctl::true_type;
|
||||
|
||||
template<typename T>
|
||||
using rebind_alloc = typename Alloc::template rebind<T>::other;
|
||||
struct rebind_alloc
|
||||
{
|
||||
using other = typename Alloc::template rebind<T>::other;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using rebind_traits = allocator_traits<rebind_alloc<T>>;
|
||||
using rebind_traits = allocator_traits<typename rebind_alloc<T>::other>;
|
||||
|
||||
__attribute__((__always_inline__)) static pointer allocate(Alloc& a,
|
||||
size_type n)
|
||||
static pointer allocate(Alloc& a, size_type n)
|
||||
{
|
||||
return a.allocate(n);
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static void deallocate(Alloc& a,
|
||||
pointer p,
|
||||
size_type n)
|
||||
static void deallocate(Alloc& a, pointer p, size_type n)
|
||||
{
|
||||
a.deallocate(p, n);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
__attribute__((__always_inline__)) static void construct(Alloc& a,
|
||||
T* p,
|
||||
Args&&... args)
|
||||
static void construct(Alloc& a, T* p, Args&&... args)
|
||||
{
|
||||
::new ((void*)p) T(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
__attribute__((__always_inline__)) static void destroy(Alloc& a, T* p)
|
||||
static void destroy(Alloc& a, T* p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static size_type max_size(
|
||||
const Alloc& a) noexcept
|
||||
static size_type max_size(const Alloc& a) noexcept
|
||||
{
|
||||
return __PTRDIFF_MAX__ / sizeof(value_type);
|
||||
return a.max_size();
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) static Alloc
|
||||
select_on_container_copy_construction(const Alloc& a)
|
||||
static Alloc select_on_container_copy_construction(const Alloc& a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
+6
-2
@@ -37,24 +37,28 @@ struct array
|
||||
constexpr reference at(size_type pos)
|
||||
{
|
||||
if (pos >= N)
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= N)
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr reference operator[](size_type pos)
|
||||
{
|
||||
if (pos >= N)
|
||||
__builtin_trap();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference operator[](size_type pos) const
|
||||
{
|
||||
if (pos >= N)
|
||||
__builtin_trap();
|
||||
return elems[pos];
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class bad_alloc : public exception
|
||||
class bad_alloc : public ctl::exception
|
||||
{
|
||||
public:
|
||||
bad_alloc() noexcept = default;
|
||||
|
||||
+8
-7
@@ -16,15 +16,16 @@ template<typename T>
|
||||
struct decay
|
||||
{
|
||||
private:
|
||||
typedef typename remove_reference<T>::type U;
|
||||
typedef typename ctl::remove_reference<T>::type U;
|
||||
|
||||
public:
|
||||
typedef typename conditional<
|
||||
is_array<U>::value,
|
||||
typename remove_extent<U>::type*,
|
||||
typename conditional<is_function<U>::value,
|
||||
typename add_pointer<U>::type,
|
||||
typename remove_cv<U>::type>::type>::type type;
|
||||
typedef typename ctl::conditional<
|
||||
ctl::is_array<U>::value,
|
||||
typename ctl::remove_extent<U>::type*,
|
||||
typename ctl::conditional<ctl::is_function<U>::value,
|
||||
typename ctl::add_pointer<U>::type,
|
||||
typename ctl::remove_cv<U>::type>::type>::type
|
||||
type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
+7
-5
@@ -8,28 +8,30 @@
|
||||
namespace ctl {
|
||||
|
||||
template<class InputIter>
|
||||
constexpr typename iterator_traits<InputIter>::difference_type
|
||||
constexpr typename ctl::iterator_traits<InputIter>::difference_type
|
||||
distance_impl(InputIter first, InputIter last, input_iterator_tag)
|
||||
{
|
||||
typename iterator_traits<InputIter>::difference_type res(0);
|
||||
typename ctl::iterator_traits<InputIter>::difference_type res(0);
|
||||
for (; first != last; ++first)
|
||||
++res;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class RandIter>
|
||||
constexpr typename iterator_traits<RandIter>::difference_type
|
||||
constexpr typename ctl::iterator_traits<RandIter>::difference_type
|
||||
distance_impl(RandIter first, RandIter last, random_access_iterator_tag)
|
||||
{
|
||||
return last - first;
|
||||
}
|
||||
|
||||
template<class InputIter>
|
||||
constexpr typename iterator_traits<InputIter>::difference_type
|
||||
constexpr typename ctl::iterator_traits<InputIter>::difference_type
|
||||
distance(InputIter first, InputIter last)
|
||||
{
|
||||
return distance_impl(
|
||||
first, last, typename iterator_traits<InputIter>::iterator_category());
|
||||
first,
|
||||
last,
|
||||
typename ctl::iterator_traits<InputIter>::iterator_category());
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "dubble.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
const double_conversion::DoubleToStringConverter kDoubleToPrintfG(
|
||||
double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
|
||||
double_conversion::DoubleToStringConverter::NO_TRAILING_ZERO,
|
||||
"inf",
|
||||
"nan",
|
||||
'e',
|
||||
-6,
|
||||
10, // let 32-bit ints be represented without exponent
|
||||
6,
|
||||
0,
|
||||
0);
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,13 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
#define COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
#include "third_party/double-conversion/double-to-string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_DUBBLE_H_
|
||||
@@ -11,10 +11,12 @@ struct integral_constant
|
||||
static constexpr T value = v;
|
||||
typedef T value_type;
|
||||
typedef integral_constant type;
|
||||
|
||||
constexpr operator value_type() const noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr value_type operator()() const noexcept
|
||||
{
|
||||
return value;
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "ios.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
ios::ios(FILE* file) : file_(file)
|
||||
{
|
||||
}
|
||||
|
||||
ios::~ios() = default;
|
||||
|
||||
ios&
|
||||
ios::operator=(ios&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
file_ = other.file_;
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,27 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IOS_H_
|
||||
#define CTL_IOS_H_
|
||||
#include "ios_base.h"
|
||||
|
||||
struct FILE;
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class ios : public ios_base
|
||||
{
|
||||
public:
|
||||
explicit ios(FILE*);
|
||||
virtual ~ios();
|
||||
|
||||
protected:
|
||||
ios& operator=(ios&&) noexcept;
|
||||
FILE* file_;
|
||||
|
||||
private:
|
||||
ios(const ios&) = delete;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IOS_H_
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "ios_base.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
ios_base::ios_base() : state_(goodbit), flags_(skipws | dec)
|
||||
{
|
||||
}
|
||||
|
||||
ios_base::~ios_base() = default;
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::flags() const
|
||||
{
|
||||
return static_cast<ios_base::fmtflags>(flags_);
|
||||
}
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::flags(fmtflags fmtfl)
|
||||
{
|
||||
int old = flags_;
|
||||
flags_ = fmtfl;
|
||||
return static_cast<ios_base::fmtflags>(old);
|
||||
}
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::setf(fmtflags fmtfl)
|
||||
{
|
||||
int old = flags_;
|
||||
flags_ |= fmtfl;
|
||||
return static_cast<ios_base::fmtflags>(old);
|
||||
}
|
||||
|
||||
ios_base::fmtflags
|
||||
ios_base::setf(fmtflags fmtfl, fmtflags mask)
|
||||
{
|
||||
int old = flags_;
|
||||
flags_ = (flags_ & ~mask) | (fmtfl & mask);
|
||||
return static_cast<ios_base::fmtflags>(old);
|
||||
}
|
||||
|
||||
void
|
||||
ios_base::unsetf(fmtflags mask)
|
||||
{
|
||||
flags_ &= ~mask;
|
||||
}
|
||||
|
||||
ios_base::iostate
|
||||
ios_base::rdstate() const
|
||||
{
|
||||
return static_cast<ios_base::iostate>(state_);
|
||||
}
|
||||
|
||||
void
|
||||
ios_base::clear(int state)
|
||||
{
|
||||
state_ = state;
|
||||
}
|
||||
|
||||
void
|
||||
ios_base::setstate(int state)
|
||||
{
|
||||
state_ |= state;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::good() const
|
||||
{
|
||||
return state_ == goodbit;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::eof() const
|
||||
{
|
||||
return (state_ & eofbit) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::fail() const
|
||||
{
|
||||
return (state_ & (failbit | badbit)) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::bad() const
|
||||
{
|
||||
return (state_ & badbit) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ios_base::operator!() const
|
||||
{
|
||||
return fail();
|
||||
}
|
||||
|
||||
ios_base::operator bool() const
|
||||
{
|
||||
return !fail();
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,86 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IOS_BASE_H_
|
||||
#define CTL_IOS_BASE_H_
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class ios_base
|
||||
{
|
||||
public:
|
||||
typedef size_t streamsize;
|
||||
|
||||
enum iostate
|
||||
{
|
||||
goodbit = 0,
|
||||
badbit = 1,
|
||||
failbit = 2,
|
||||
eofbit = 4
|
||||
};
|
||||
|
||||
enum fmtflags
|
||||
{
|
||||
boolalpha = 1 << 0,
|
||||
dec = 1 << 1,
|
||||
fixed = 1 << 2,
|
||||
hex = 1 << 3,
|
||||
internal = 1 << 4,
|
||||
left = 1 << 5,
|
||||
oct = 1 << 6,
|
||||
right = 1 << 7,
|
||||
scientific = 1 << 8,
|
||||
showbase = 1 << 9,
|
||||
showpoint = 1 << 10,
|
||||
showpos = 1 << 11,
|
||||
skipws = 1 << 12,
|
||||
unitbuf = 1 << 13,
|
||||
uppercase = 1 << 14,
|
||||
adjustfield = left | right | internal,
|
||||
basefield = dec | oct | hex,
|
||||
floatfield = scientific | fixed
|
||||
};
|
||||
|
||||
enum openmode
|
||||
{
|
||||
app = 1 << 0,
|
||||
binary = 1 << 1,
|
||||
in = 1 << 2,
|
||||
out = 1 << 3,
|
||||
trunc = 1 << 4,
|
||||
ate = 1 << 5
|
||||
};
|
||||
|
||||
protected:
|
||||
ios_base();
|
||||
virtual ~ios_base();
|
||||
|
||||
int state_;
|
||||
int flags_;
|
||||
|
||||
public:
|
||||
fmtflags flags() const;
|
||||
fmtflags flags(fmtflags);
|
||||
fmtflags setf(fmtflags);
|
||||
fmtflags setf(fmtflags, fmtflags);
|
||||
void unsetf(fmtflags);
|
||||
|
||||
iostate rdstate() const;
|
||||
void clear(int = goodbit);
|
||||
void setstate(int);
|
||||
|
||||
bool good() const;
|
||||
bool eof() const;
|
||||
bool fail() const;
|
||||
bool bad() const;
|
||||
|
||||
bool operator!() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
private:
|
||||
ios_base(const ios_base&) = delete;
|
||||
ios_base& operator=(const ios_base&) = delete;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IOS_BASE_H_
|
||||
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_ABSTRACT_H_
|
||||
#define CTL_IS_ABSTRACT_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_abstract : public ctl::integral_constant<bool, __is_abstract(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_abstract_v = __is_abstract(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_ABSTRACT_H_
|
||||
+3
-3
@@ -7,15 +7,15 @@
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_array : false_type
|
||||
struct is_array : ctl::false_type
|
||||
{};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct is_array<T[N]> : true_type
|
||||
struct is_array<T[N]> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_array<T[]> : true_type
|
||||
struct is_array<T[]> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_BASE_OF_H_
|
||||
#define CTL_IS_BASE_OF_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
struct is_base_of
|
||||
: public ctl::integral_constant<bool, __is_base_of(Base, Derived)>
|
||||
{};
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
inline constexpr bool is_base_of_v = __is_base_of(Base, Derived);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_BASE_OF_H_
|
||||
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_CLASS_H_
|
||||
#define CTL_IS_CLASS_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_class : public ctl::integral_constant<bool, __is_class(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_class_v = __is_class(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_CLASS_H_
|
||||
@@ -0,0 +1,19 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_CONSTRUCTIBLE_H_
|
||||
#define CTL_IS_CONSTRUCTIBLE_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class _Tp, class... _Args>
|
||||
struct is_constructible
|
||||
: public ctl::integral_constant<bool, __is_constructible(_Tp, _Args...)>
|
||||
{};
|
||||
|
||||
template<class _Tp, class... _Args>
|
||||
inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_CONSTRUCTIBLE_H_
|
||||
@@ -2,7 +2,6 @@
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_CONVERTIBLE_H_
|
||||
#define CTL_IS_CONVERTIBLE_H_
|
||||
|
||||
#include "ctl/integral_constant.h"
|
||||
#include "ctl/void_t.h"
|
||||
|
||||
@@ -16,7 +15,7 @@ declval() noexcept;
|
||||
namespace detail {
|
||||
|
||||
template<typename From, typename To, typename = void>
|
||||
struct is_convertible_impl : false_type
|
||||
struct is_convertible_impl : ctl::false_type
|
||||
{};
|
||||
|
||||
template<typename From, typename To>
|
||||
@@ -28,15 +27,15 @@ struct is_convertible_impl<From,
|
||||
|
||||
// Handle void types separately
|
||||
template<>
|
||||
struct is_convertible_impl<void, void> : true_type
|
||||
struct is_convertible_impl<void, void> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename To>
|
||||
struct is_convertible_impl<void, To> : false_type
|
||||
struct is_convertible_impl<void, To> : ctl::false_type
|
||||
{};
|
||||
|
||||
template<typename From>
|
||||
struct is_convertible_impl<From, void> : false_type
|
||||
struct is_convertible_impl<From, void> : ctl::false_type
|
||||
{};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_EMPTY_H_
|
||||
#define CTL_IS_EMPTY_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_empty : public ctl::integral_constant<bool, __is_empty(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_empty_v = __is_empty(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_EMPTY_H_
|
||||
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_ENUM_H_
|
||||
#define CTL_IS_ENUM_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_enum : public ctl::integral_constant<bool, __is_enum(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_enum_v = __is_enum(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_ENUM_H_
|
||||
+25
-25
@@ -8,111 +8,111 @@ namespace ctl {
|
||||
|
||||
// Primary template
|
||||
template<class>
|
||||
struct is_function : false_type
|
||||
struct is_function : ctl::false_type
|
||||
{};
|
||||
|
||||
// Specializations for various function types
|
||||
|
||||
// Regular functions
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...)> : true_type
|
||||
struct is_function<Ret(Args...)> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Functions with cv-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const> : true_type
|
||||
struct is_function<Ret(Args...) const> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile> : true_type
|
||||
struct is_function<Ret(Args...) volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile> : true_type
|
||||
struct is_function<Ret(Args...) const volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Functions with ref-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...)&> : true_type
|
||||
struct is_function<Ret(Args...)&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const&> : true_type
|
||||
struct is_function<Ret(Args...) const&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile&> : true_type
|
||||
struct is_function<Ret(Args...) volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile&> : true_type
|
||||
struct is_function<Ret(Args...) const volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) &&> : true_type
|
||||
struct is_function<Ret(Args...) &&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const&&> : true_type
|
||||
struct is_function<Ret(Args...) const&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) volatile&&> : true_type
|
||||
struct is_function<Ret(Args...) volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args...) const volatile&&> : true_type
|
||||
struct is_function<Ret(Args...) const volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Variadic functions
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...)> : true_type
|
||||
struct is_function<Ret(Args..., ...)> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Variadic functions with cv-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const> : true_type
|
||||
struct is_function<Ret(Args..., ...) const> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile> : true_type
|
||||
struct is_function<Ret(Args..., ...) volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile> : true_type
|
||||
struct is_function<Ret(Args..., ...) const volatile> : ctl::true_type
|
||||
{};
|
||||
|
||||
// Variadic functions with ref-qualifiers
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...)&> : true_type
|
||||
struct is_function<Ret(Args..., ...)&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile&> : true_type
|
||||
struct is_function<Ret(Args..., ...) volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const volatile&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) &&> : true_type
|
||||
struct is_function<Ret(Args..., ...) &&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const&&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) volatile&&> : true_type
|
||||
struct is_function<Ret(Args..., ...) volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<class Ret, class... Args>
|
||||
struct is_function<Ret(Args..., ...) const volatile&&> : true_type
|
||||
struct is_function<Ret(Args..., ...) const volatile&&> : ctl::true_type
|
||||
{};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
+16
-16
@@ -7,67 +7,67 @@
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_integral : false_type
|
||||
struct is_integral : ctl::false_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<bool> : true_type
|
||||
struct is_integral<bool> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char> : true_type
|
||||
struct is_integral<char> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<signed char> : true_type
|
||||
struct is_integral<signed char> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned char> : true_type
|
||||
struct is_integral<unsigned char> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<short> : true_type
|
||||
struct is_integral<short> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned short> : true_type
|
||||
struct is_integral<unsigned short> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<int> : true_type
|
||||
struct is_integral<int> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned int> : true_type
|
||||
struct is_integral<unsigned int> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<long> : true_type
|
||||
struct is_integral<long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned long> : true_type
|
||||
struct is_integral<unsigned long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<long long> : true_type
|
||||
struct is_integral<long long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<unsigned long long> : true_type
|
||||
struct is_integral<unsigned long long> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char16_t> : true_type
|
||||
struct is_integral<char16_t> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<char32_t> : true_type
|
||||
struct is_integral<char32_t> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct is_integral<wchar_t> : true_type
|
||||
struct is_integral<wchar_t> : ctl::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_POLYMORPHIC_H_
|
||||
#define CTL_IS_POLYMORPHIC_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_polymorphic : public ctl::integral_constant<bool, __is_polymorphic(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_polymorphic_v = __is_polymorphic(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_POLYMORPHIC_H_
|
||||
@@ -0,0 +1,19 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_STANDARD_LAYOUT_H_
|
||||
#define CTL_IS_STANDARD_LAYOUT_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_standard_layout
|
||||
: public ctl::integral_constant<bool, __is_standard_layout(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_standard_layout_v = __is_standard_layout(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_STANDARD_LAYOUT_H_
|
||||
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_TRIVIAL_H_
|
||||
#define CTL_IS_TRIVIAL_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_trivial : public ctl::integral_constant<bool, __is_trivial(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_trivial_v = __is_trivial(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_TRIVIAL_H_
|
||||
@@ -0,0 +1,18 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_IS_UNION_H_
|
||||
#define CTL_IS_UNION_H_
|
||||
#include "integral_constant.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename T>
|
||||
struct is_union : public ctl::integral_constant<bool, __is_union(T)>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_union_v = __is_union(T);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_IS_UNION_H_
|
||||
+237
@@ -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
|
||||
@@ -0,0 +1,53 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ISTREAM_H_
|
||||
#define CTL_ISTREAM_H_
|
||||
#include "ios.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct string;
|
||||
|
||||
class istream : public ios
|
||||
{
|
||||
public:
|
||||
istream() = delete;
|
||||
explicit istream(FILE*);
|
||||
virtual ~istream();
|
||||
|
||||
istream& operator>>(char&);
|
||||
istream& operator>>(int&);
|
||||
istream& operator>>(long&);
|
||||
istream& operator>>(double&);
|
||||
istream& operator>>(bool&);
|
||||
istream& operator>>(ctl::string&);
|
||||
istream& operator>>(istream& (*)(istream&));
|
||||
|
||||
int get();
|
||||
istream& get(char&);
|
||||
istream& getline(char*, streamsize);
|
||||
istream& getline(char*, streamsize, char);
|
||||
istream& read(char*, streamsize);
|
||||
streamsize gcount() const;
|
||||
|
||||
int peek();
|
||||
istream& ignore(streamsize = 1, int = -1);
|
||||
|
||||
istream(istream&&) noexcept;
|
||||
istream& operator=(istream&&) noexcept;
|
||||
|
||||
private:
|
||||
streamsize gcount_;
|
||||
|
||||
istream(const istream&) = delete;
|
||||
istream& operator=(const istream&) = delete;
|
||||
};
|
||||
|
||||
extern istream cin;
|
||||
|
||||
istream&
|
||||
ws(istream& is);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ISTREAM_H_
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,41 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ISTRINGSTREAM_H_
|
||||
#define CTL_ISTRINGSTREAM_H_
|
||||
#include "ios_base.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class istringstream : public ios_base
|
||||
{
|
||||
public:
|
||||
istringstream();
|
||||
explicit istringstream(const ctl::string_view&);
|
||||
|
||||
string str() const;
|
||||
void str(const string&);
|
||||
|
||||
istringstream& operator>>(char&);
|
||||
istringstream& operator>>(char*);
|
||||
istringstream& operator>>(ctl::string&);
|
||||
istringstream& operator>>(short&);
|
||||
istringstream& operator>>(unsigned short&);
|
||||
istringstream& operator>>(int&);
|
||||
istringstream& operator>>(unsigned int&);
|
||||
istringstream& operator>>(long&);
|
||||
istringstream& operator>>(unsigned long&);
|
||||
istringstream& operator>>(float&);
|
||||
istringstream& operator>>(double&);
|
||||
|
||||
private:
|
||||
ctl::string buffer_;
|
||||
size_t read_pos_;
|
||||
|
||||
template<typename T>
|
||||
istringstream& read_numeric(T&);
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ISTRINGSTREAM_H_
|
||||
+22
-11
@@ -2,12 +2,33 @@
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_ITERATOR_TRAITS_H_
|
||||
#define CTL_ITERATOR_TRAITS_H_
|
||||
#include "iterator.h"
|
||||
#include "utility.h"
|
||||
#include "void_t.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<class Iterator>
|
||||
template<typename Iterator, typename = void>
|
||||
struct iterator_traits
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct iterator_traits<T*>
|
||||
{
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
using iterator_category = ctl::random_access_iterator_tag;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
struct iterator_traits<Iterator,
|
||||
ctl::void_t<typename Iterator::iterator_category,
|
||||
typename Iterator::value_type,
|
||||
typename Iterator::difference_type,
|
||||
typename Iterator::pointer,
|
||||
typename Iterator::reference>>
|
||||
{
|
||||
using iterator_category = typename Iterator::iterator_category;
|
||||
using value_type = typename Iterator::value_type;
|
||||
@@ -16,16 +37,6 @@ struct iterator_traits
|
||||
using reference = typename Iterator::reference;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct iterator_traits<T*>
|
||||
{
|
||||
using iterator_category = void*; // We don't actually use this
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_ITERATOR_TRAITS_H_
|
||||
@@ -152,12 +152,12 @@ class map
|
||||
|
||||
Value& operator[](const Key& key)
|
||||
{
|
||||
return ((data_.insert(make_pair(key, Value()))).first)->second;
|
||||
return ((data_.insert(ctl::make_pair(key, Value()))).first)->second;
|
||||
}
|
||||
|
||||
Value& operator[](Key&& key)
|
||||
{
|
||||
return ((data_.insert(make_pair(ctl::move(key), Value()))).first)
|
||||
return ((data_.insert(ctl::make_pair(ctl::move(key), Value()))).first)
|
||||
->second;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class map
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ class map
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
throw ctl::out_of_range("out of range");
|
||||
throw ctl::out_of_range();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ class map
|
||||
|
||||
size_type erase(const Key& key)
|
||||
{
|
||||
return data_.erase(make_pair(key, Value()));
|
||||
return data_.erase(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
void swap(map& other) noexcept
|
||||
@@ -259,47 +259,47 @@ class map
|
||||
|
||||
iterator find(const Key& key)
|
||||
{
|
||||
return data_.find(make_pair(key, Value()));
|
||||
return data_.find(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator find(const Key& key) const
|
||||
{
|
||||
return data_.find(make_pair(key, Value()));
|
||||
return data_.find(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
size_type count(const Key& key) const
|
||||
{
|
||||
return data_.count(make_pair(key, Value()));
|
||||
return data_.count(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
iterator lower_bound(const Key& key)
|
||||
{
|
||||
return data_.lower_bound(make_pair(key, Value()));
|
||||
return data_.lower_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const Key& key) const
|
||||
{
|
||||
return data_.lower_bound(make_pair(key, Value()));
|
||||
return data_.lower_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
iterator upper_bound(const Key& key)
|
||||
{
|
||||
return data_.upper_bound(make_pair(key, Value()));
|
||||
return data_.upper_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const Key& key) const
|
||||
{
|
||||
return data_.upper_bound(make_pair(key, Value()));
|
||||
return data_.upper_bound(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
ctl::pair<iterator, iterator> equal_range(const Key& key)
|
||||
{
|
||||
return data_.equal_range(make_pair(key, Value()));
|
||||
return data_.equal_range(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
ctl::pair<const_iterator, const_iterator> equal_range(const Key& key) const
|
||||
{
|
||||
return data_.equal_range(make_pair(key, Value()));
|
||||
return data_.equal_range(ctl::make_pair(key, Value()));
|
||||
}
|
||||
|
||||
key_compare key_comp() const
|
||||
|
||||
+8
-4
@@ -11,17 +11,20 @@ class mutex
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
pthread_mutex_init(&m_, nullptr);
|
||||
if (pthread_mutex_init(&m_, nullptr))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
~mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&m_);
|
||||
if (pthread_mutex_destroy(&m_))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_);
|
||||
if (pthread_mutex_lock(&m_))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
@@ -31,7 +34,8 @@ class mutex
|
||||
|
||||
void unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_);
|
||||
if (pthread_mutex_unlock(&m_))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "ostream.h"
|
||||
#include "dubble.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "string_view.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
ostream cout(stdout);
|
||||
ostream cerr(stderr);
|
||||
|
||||
ostream::~ostream() = default;
|
||||
|
||||
ostream::ostream(FILE* file) : ios(file)
|
||||
{
|
||||
}
|
||||
|
||||
ostream::ostream(ostream&& other) noexcept : ios(other.file_)
|
||||
{
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator=(ostream&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
file_ = other.file_;
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(const char* str)
|
||||
{
|
||||
if (good() && str)
|
||||
if (fputs(str, file_) < 0)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(char c)
|
||||
{
|
||||
if (good())
|
||||
if (fputc(c, file_) == EOF)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(int n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
FormatInt32(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(unsigned n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
FormatUint32(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
FormatInt64(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(unsigned long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
FormatUint64(buf, n);
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(float f)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortestSingle(f, &b);
|
||||
b.Finalize();
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(double d)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortest(d, &b);
|
||||
b.Finalize();
|
||||
if (fputs(buf, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(const string_view& s)
|
||||
{
|
||||
if (good() && s.size())
|
||||
if (!fwrite(s.data(), s.size(), 1, file_))
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(bool b)
|
||||
{
|
||||
if (good()) {
|
||||
const char* value =
|
||||
(flags() & boolalpha) ? (b ? "true" : "false") : (b ? "1" : "0");
|
||||
if (fputs(value, file_) < 0)
|
||||
setstate(badbit);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::operator<<(ostream& (*manip)(ostream&))
|
||||
{
|
||||
return manip(*this);
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::put(char c)
|
||||
{
|
||||
if (good())
|
||||
if (fputc(c, file_) == EOF)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::write(const char* s, streamsize n)
|
||||
{
|
||||
if (good())
|
||||
if (fwrite(s, 1, n, file_) != static_cast<size_t>(n))
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ostream::flush()
|
||||
{
|
||||
if (good())
|
||||
if (fflush(file_) != 0)
|
||||
setstate(badbit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostream&
|
||||
endl(ostream& os)
|
||||
{
|
||||
return os.put('\n').flush();
|
||||
}
|
||||
|
||||
ostream&
|
||||
ends(ostream& os)
|
||||
{
|
||||
return os.put('\0');
|
||||
}
|
||||
|
||||
ostream&
|
||||
flush(ostream& os)
|
||||
{
|
||||
return os.flush();
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,56 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_OSTREAM_H_
|
||||
#define CTL_OSTREAM_H_
|
||||
#include "ios.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
struct string_view;
|
||||
|
||||
class ostream : public ios
|
||||
{
|
||||
public:
|
||||
ostream() = delete;
|
||||
explicit ostream(FILE*);
|
||||
virtual ~ostream();
|
||||
|
||||
ostream& operator<<(const char*);
|
||||
ostream& operator<<(bool);
|
||||
ostream& operator<<(char);
|
||||
ostream& operator<<(int);
|
||||
ostream& operator<<(unsigned);
|
||||
ostream& operator<<(long);
|
||||
ostream& operator<<(unsigned long);
|
||||
ostream& operator<<(float);
|
||||
ostream& operator<<(double);
|
||||
ostream& operator<<(const ctl::string_view&);
|
||||
ostream& operator<<(ostream& (*)(ostream&));
|
||||
|
||||
ostream& put(char);
|
||||
ostream& write(const char*, streamsize);
|
||||
ostream& flush();
|
||||
|
||||
ostream(ostream&&) noexcept;
|
||||
ostream& operator=(ostream&&) noexcept;
|
||||
|
||||
private:
|
||||
ostream(const ostream&) = delete;
|
||||
ostream& operator=(const ostream&) = delete;
|
||||
};
|
||||
|
||||
extern ostream cout;
|
||||
extern ostream cerr;
|
||||
|
||||
ostream&
|
||||
endl(ostream&);
|
||||
|
||||
ostream&
|
||||
ends(ostream&);
|
||||
|
||||
ostream&
|
||||
flush(ostream&);
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_OSTREAM_H_
|
||||
@@ -0,0 +1,150 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "ostringstream.h"
|
||||
#include "dubble.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
ostringstream::ostringstream() : buffer_(), write_pos_(0)
|
||||
{
|
||||
}
|
||||
|
||||
ostringstream::ostringstream(const string_view& str)
|
||||
: buffer_(str), write_pos_(0)
|
||||
{
|
||||
}
|
||||
|
||||
string
|
||||
ostringstream::str() const
|
||||
{
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
void
|
||||
ostringstream::str(const string& s)
|
||||
{
|
||||
buffer_ = s;
|
||||
write_pos_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ostringstream::clear()
|
||||
{
|
||||
ios_base::clear();
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(char c)
|
||||
{
|
||||
if (good()) {
|
||||
if (write_pos_ < buffer_.size()) {
|
||||
buffer_[write_pos_++] = c;
|
||||
} else {
|
||||
buffer_.push_back(c);
|
||||
++write_pos_;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(const string_view& s)
|
||||
{
|
||||
if (good()) {
|
||||
if (write_pos_ + s.size() <= buffer_.size()) {
|
||||
buffer_.replace(write_pos_, s.size(), s);
|
||||
} else {
|
||||
buffer_.replace(write_pos_, buffer_.size() - write_pos_, s);
|
||||
buffer_.append(s.substr(buffer_.size() - write_pos_));
|
||||
}
|
||||
write_pos_ += s.size();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(int n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
*this << string_view(buf, FormatInt32(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(unsigned n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[12];
|
||||
*this << string_view(buf, FormatUint32(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
*this << string_view(buf, FormatInt64(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(unsigned long n)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[21];
|
||||
*this << string_view(buf, FormatUint64(buf, n) - buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(float f)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortestSingle(f, &b);
|
||||
b.Finalize();
|
||||
*this << string_view(buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ostringstream&
|
||||
ostringstream::operator<<(double d)
|
||||
{
|
||||
if (good()) {
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortest(d, &b);
|
||||
b.Finalize();
|
||||
*this << string_view(buf);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
@@ -0,0 +1,36 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_OSTRINGSTREAM_H_
|
||||
#define CTL_OSTRINGSTREAM_H_
|
||||
#include "ios_base.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class ostringstream : public ios_base
|
||||
{
|
||||
public:
|
||||
ostringstream();
|
||||
explicit ostringstream(const ctl::string_view&);
|
||||
|
||||
ctl::string str() const;
|
||||
void str(const ctl::string& s);
|
||||
void clear();
|
||||
|
||||
ostringstream& operator<<(char);
|
||||
ostringstream& operator<<(const ctl::string_view&);
|
||||
ostringstream& operator<<(int);
|
||||
ostringstream& operator<<(unsigned int);
|
||||
ostringstream& operator<<(long);
|
||||
ostringstream& operator<<(unsigned long);
|
||||
ostringstream& operator<<(float);
|
||||
ostringstream& operator<<(double);
|
||||
|
||||
private:
|
||||
ctl::string buffer_;
|
||||
size_t write_pos_;
|
||||
};
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // CTL_OSTRINGSTREAM_H_
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ctl {
|
||||
|
||||
class out_of_range : public exception
|
||||
class out_of_range : public ctl::exception
|
||||
{
|
||||
public:
|
||||
out_of_range() noexcept = default;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef CTL_REQUIRE_INPUT_ITERATOR_H_
|
||||
#define CTL_REQUIRE_INPUT_ITERATOR_H_
|
||||
#include "enable_if.h"
|
||||
#include "is_convertible.h"
|
||||
#include "iterator.h"
|
||||
#include "iterator_traits.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
template<typename InputIt>
|
||||
using require_input_iterator = typename ctl::enable_if<
|
||||
ctl::is_convertible<typename ctl::iterator_traits<InputIt>::iterator_category,
|
||||
ctl::input_iterator_tag>::value>::type;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif /* CTL_REQUIRE_INPUT_ITERATOR_H_ */
|
||||
@@ -13,11 +13,12 @@ class reverse_iterator
|
||||
public:
|
||||
using iterator_type = Iterator;
|
||||
using iterator_category =
|
||||
typename iterator_traits<Iterator>::iterator_category;
|
||||
using value_type = typename iterator_traits<Iterator>::value_type;
|
||||
using difference_type = typename iterator_traits<Iterator>::difference_type;
|
||||
using pointer = typename iterator_traits<Iterator>::pointer;
|
||||
using reference = typename iterator_traits<Iterator>::reference;
|
||||
typename ctl::iterator_traits<Iterator>::iterator_category;
|
||||
using value_type = typename ctl::iterator_traits<Iterator>::value_type;
|
||||
using difference_type =
|
||||
typename ctl::iterator_traits<Iterator>::difference_type;
|
||||
using pointer = typename ctl::iterator_traits<Iterator>::pointer;
|
||||
using reference = typename ctl::iterator_traits<Iterator>::reference;
|
||||
|
||||
constexpr reverse_iterator() : current()
|
||||
{
|
||||
|
||||
@@ -8,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
@@ -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
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
//
|
||||
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for
|
||||
// any purpose with or without fee is hereby granted, provided that the
|
||||
// above copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "dubble.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/math.h"
|
||||
#include "string.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
namespace ctl {
|
||||
|
||||
extern const double_conversion::DoubleToStringConverter kDoubleToPrintfG;
|
||||
|
||||
string
|
||||
to_string(int value) noexcept
|
||||
{
|
||||
char buf[12];
|
||||
return { buf, FormatInt32(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(unsigned value) noexcept
|
||||
{
|
||||
char buf[12];
|
||||
return { buf, FormatUint32(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatInt64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(unsigned long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatUint64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(long long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatInt64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(unsigned long long value) noexcept
|
||||
{
|
||||
char buf[21];
|
||||
return { buf, FormatUint64(buf, value) - buf };
|
||||
}
|
||||
|
||||
string
|
||||
to_string(float value) noexcept
|
||||
{
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortestSingle(value, &b);
|
||||
b.Finalize();
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
string
|
||||
to_string(double value) noexcept
|
||||
{
|
||||
char buf[128];
|
||||
double_conversion::StringBuilder b(buf, sizeof(buf));
|
||||
kDoubleToPrintfG.ToShortest(value, &b);
|
||||
b.Finalize();
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
string
|
||||
to_string(long double value) noexcept
|
||||
{
|
||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
return to_string((double)value);
|
||||
#else
|
||||
char buf[128];
|
||||
#if LDBL_MANT_DIG == 113
|
||||
g_Qfmt_p(buf, &value, 16, 128, NIK(2, 0, 0));
|
||||
#elif LDBL_MANT_DIG == 64
|
||||
g_xfmt_p(buf, &value, 16, 128, NIK(2, 0, 0));
|
||||
#else
|
||||
#error "unsupported long double"
|
||||
#endif
|
||||
return string(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ctl
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
|
||||
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||
#ifndef COSMOPOLITAN_CTL_UTILITY_H_
|
||||
#define COSMOPOLITAN_CTL_UTILITY_H_
|
||||
#ifndef CTL_UTILITY_H_
|
||||
#define CTL_UTILITY_H_
|
||||
#include "remove_reference.h"
|
||||
|
||||
namespace ctl {
|
||||
@@ -66,4 +66,4 @@ declval() noexcept;
|
||||
|
||||
} // namespace ctl
|
||||
|
||||
#endif // COSMOPOLITAN_CTL_UTILITY_H_
|
||||
#endif // CTL_UTILITY_H_
|
||||
+14
-8
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__)
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -42,4 +42,3 @@
|
||||
void *malloc(size_t n) {
|
||||
return dlmalloc(n);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
Vendored
+1
@@ -427,6 +427,7 @@ is_bourne_compatible_shell (const char *path)
|
||||
"sh",
|
||||
"bash",
|
||||
"dash",
|
||||
"cocmd",
|
||||
"ksh",
|
||||
"rksh",
|
||||
"zsh",
|
||||
|
||||
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
@@ -5364,6 +5364,7 @@ static const luaL_Reg kLuaFuncs[] = {
|
||||
{"Uncompress", LuaUncompress}, //
|
||||
{"Underlong", LuaUnderlong}, //
|
||||
{"UuidV4", LuaUuidV4}, //
|
||||
{"UuidV7", LuaUuidV7}, //
|
||||
{"VisualizeControlCodes", LuaVisualizeControlCodes}, //
|
||||
{"Write", LuaWrite}, //
|
||||
{"bin", LuaBin}, //
|
||||
|
||||
Reference in new issue
Block a user