Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 74 additions & 3 deletions include/__psychicstd_algo
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#pragma once
#include <cstddef>
#include <iterator>
#include <utility>

// Minimal algorithm helpers so containers (map, set, list) don't pull in all of
// <algorithm> for one or two functions. Reserved __ names, so they never clash
// with the real <algorithm> if it is also included.
// Minimal algorithm helpers so containers (map, set, list, queue) don't pull
// in all of <algorithm> for one or two functions. Reserved __ names, so they
// never clash with the real <algorithm> if it is also included.

namespace std {

Expand Down Expand Up @@ -49,4 +52,72 @@ constexpr bool __lexicographical_compare(It1 f1, It1 l1, It2 f2, It2 l2) {
return f1 == l1 && f2 != l2;
}

// Heap operations (used by priority_queue and by <algorithm>'s sort_heap).
template <typename It, typename Compare>
void __push_heap(It first, ptrdiff_t hole, ptrdiff_t top, Compare cmp,
typename iterator_traits<It>::value_type val) {
ptrdiff_t parent = (hole - 1) / 2;
while (hole > top && cmp(*(first + parent), val)) {
*(first + hole) = static_cast<decltype(val)&&>(*(first + parent));
hole = parent;
parent = (hole - 1) / 2;
}
*(first + hole) = static_cast<decltype(val)&&>(val);
}

template <typename It, typename Compare>
void push_heap(It first, It last, Compare cmp) {
if (last - first > 1) {
auto val = std::move(*(last - 1));
__push_heap(first, last - first - 1, ptrdiff_t(0), cmp, std::move(val));
}
}
template <typename It> void push_heap(It first, It last) {
push_heap(first, last, [](const auto& a, const auto& b) { return a < b; });
}

template <typename It, typename Compare>
void __adjust_heap(It first, ptrdiff_t hole, ptrdiff_t len, Compare cmp,
typename iterator_traits<It>::value_type val) {
ptrdiff_t top = hole;
ptrdiff_t rchild = 2 * hole + 2;
while (rchild < len) {
if (cmp(*(first + rchild), *(first + (rchild - 1))))
--rchild;
*(first + hole) = static_cast<decltype(val)&&>(*(first + rchild));
hole = rchild;
rchild = 2 * hole + 2;
}
if (rchild == len) {
*(first + hole) = static_cast<decltype(val)&&>(*(first + (rchild - 1)));
hole = rchild - 1;
}
__push_heap(first, hole, top, cmp, std::move(val));
}

template <typename It, typename Compare>
void pop_heap(It first, It last, Compare cmp) {
if (last - first > 1) {
--last;
auto val = std::move(*last);
*last = std::move(*first);
__adjust_heap(first, ptrdiff_t(0), last - first, cmp, std::move(val));
}
}
template <typename It> void pop_heap(It first, It last) {
pop_heap(first, last, [](const auto& a, const auto& b) { return a < b; });
}

template <typename It, typename Compare>
void make_heap(It first, It last, Compare cmp) {
ptrdiff_t n = last - first;
for (ptrdiff_t i = n / 2 - 1; i >= 0; --i) {
auto val = std::move(*(first + i));
__adjust_heap(first, i, n, cmp, std::move(val));
}
}
template <typename It> void make_heap(It first, It last) {
make_heap(first, last, [](const auto& a, const auto& b) { return a < b; });
}

} // namespace std
70 changes: 3 additions & 67 deletions include/algorithm
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <__psychicstd_algo>
#include <functional>
#include <initializer_list>
#include <iterator>
Expand Down Expand Up @@ -961,73 +962,8 @@ OutIt set_symmetric_difference(It1 f1, It1 l1, It2 f2, It2 l2, OutIt out) {
return copy(f2, l2, out);
}

// Heap operations
template <typename It, typename Compare>
void __push_heap(It first, ptrdiff_t hole, ptrdiff_t top, Compare cmp,
typename iterator_traits<It>::value_type val) {
ptrdiff_t parent = (hole - 1) / 2;
while (hole > top && cmp(*(first + parent), val)) {
*(first + hole) = static_cast<decltype(val)&&>(*(first + parent));
hole = parent;
parent = (hole - 1) / 2;
}
*(first + hole) = static_cast<decltype(val)&&>(val);
}

template <typename It, typename Compare>
void push_heap(It first, It last, Compare cmp) {
if (last - first > 1) {
auto val = std::move(*(last - 1));
__push_heap(first, last - first - 1, ptrdiff_t(0), cmp, std::move(val));
}
}
template <typename It> void push_heap(It first, It last) {
push_heap(first, last, [](const auto& a, const auto& b) { return a < b; });
}

template <typename It, typename Compare>
void __adjust_heap(It first, ptrdiff_t hole, ptrdiff_t len, Compare cmp,
typename iterator_traits<It>::value_type val) {
ptrdiff_t top = hole;
ptrdiff_t rchild = 2 * hole + 2;
while (rchild < len) {
if (cmp(*(first + rchild), *(first + (rchild - 1))))
--rchild;
*(first + hole) = static_cast<decltype(val)&&>(*(first + rchild));
hole = rchild;
rchild = 2 * hole + 2;
}
if (rchild == len) {
*(first + hole) = static_cast<decltype(val)&&>(*(first + (rchild - 1)));
hole = rchild - 1;
}
__push_heap(first, hole, top, cmp, std::move(val));
}

template <typename It, typename Compare>
void pop_heap(It first, It last, Compare cmp) {
if (last - first > 1) {
--last;
auto val = std::move(*last);
*last = std::move(*first);
__adjust_heap(first, ptrdiff_t(0), last - first, cmp, std::move(val));
}
}
template <typename It> void pop_heap(It first, It last) {
pop_heap(first, last, [](const auto& a, const auto& b) { return a < b; });
}

template <typename It, typename Compare>
void make_heap(It first, It last, Compare cmp) {
ptrdiff_t n = last - first;
for (ptrdiff_t i = n / 2 - 1; i >= 0; --i) {
auto val = std::move(*(first + i));
__adjust_heap(first, i, n, cmp, std::move(val));
}
}
template <typename It> void make_heap(It first, It last) {
make_heap(first, last, [](const auto& a, const auto& b) { return a < b; });
}
// push_heap/pop_heap/make_heap live in <__psychicstd_algo> so <queue>'s
// priority_queue can use them without pulling in all of <algorithm>.

template <typename It, typename Compare>
void sort_heap(It first, It last, Compare cmp) {
Expand Down
6 changes: 6 additions & 0 deletions include/csignal
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
#pragma once
#include <signal.h>

namespace std {
using ::raise;
using ::sig_atomic_t;
using ::signal;
} // namespace std
1 change: 1 addition & 0 deletions include/queue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <__psychicstd_algo>
#include <deque>
#include <functional>
#include <vector>
Expand Down
7 changes: 7 additions & 0 deletions include/typeindex
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,11 @@ public:
const char* name() const noexcept { return ptr_->name(); }
};

template <typename T> struct hash;
template <> struct hash<type_index> {
size_t operator()(const type_index& ti) const noexcept {
return ti.hash_code();
}
};

} // namespace std
27 changes: 27 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,31 @@ set(TESTS
test_any
test_array
test_atomic
test_bit
test_cassert
test_cctype
test_cerrno
test_cfenv
test_cfloat
test_chrono
test_cinttypes
test_ciso646
test_climits
test_clocale
test_cmath
test_compare
test_complex
test_concepts
test_condition_variable
test_csignal
test_cstdarg
test_cstddef
test_cstdint
test_cstdio
test_cstdlib
test_cstring
test_ctime
test_cwchar
test_deque
test_exception
test_filesystem
Expand All @@ -23,17 +42,21 @@ set(TESTS
test_initializer_list
test_iomanip
test_ios
test_iosfwd
test_iostream
test_istream
test_iterator
test_limits
test_list
test_locale
test_map
test_memory
test_mutex
test_new
test_numeric
test_optional
test_ostream
test_queue
test_random
test_ranges
test_ratio
Expand All @@ -43,18 +66,22 @@ set(TESTS
test_sstream
test_stack
test_stdexcept
test_streambuf
test_string
test_string_view
test_system_error
test_thread
test_tuple
test_type_traits
test_typeindex
test_typeinfo
test_unordered_map
test_unordered_set
test_utility
test_valarray
test_variant
test_vector
test_version
)

foreach(t ${TESTS})
Expand Down
29 changes: 29 additions & 0 deletions tests/test_bit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <bit>
#include <cassert>
#include <cmath>
#include <cstdint>

// Quake III's fast inverse square root: bit_cast the float's bit pattern to
// an integer, do the "magic number" trick, bit_cast back. A classic exercise
// of bit_cast round-tripping a value's representation between types.
float fast_inverse_sqrt(float x) {
float xhalf = 0.5f * x;
std::uint32_t i = std::bit_cast<std::uint32_t>(x);
i = 0x5f3759df - (i >> 1);
float y = std::bit_cast<float>(i);
y = y * (1.5f - xhalf * y * y); // one Newton iteration
return y;
}

int main() {
static_assert(std::bit_cast<std::uint32_t>(0.0f) == 0u);

float y = fast_inverse_sqrt(4.0f);
float expected = 1.0f / std::sqrt(4.0f);
assert(std::fabs(y - expected) < 1e-2f);

// Round-tripping through bit_cast twice must be the identity.
std::uint32_t bits = std::bit_cast<std::uint32_t>(3.14f);
float back = std::bit_cast<float>(bits);
assert(back == 3.14f);
}
32 changes: 32 additions & 0 deletions tests/test_cassert.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <cassert>

// Binary search that documents its invariants with assert(): the array must
// be sorted, and the returned index (if any) must actually contain the key.
int binary_search(const int* a, int n, int key) {
int lo = 0, hi = n - 1;
while (lo <= hi) {
assert(lo >= 0 && hi < n);
int mid = lo + (hi - lo) / 2;
assert(mid >= lo && mid <= hi);
if (a[mid] == key)
return mid;
if (a[mid] < key)
lo = mid + 1;
else
hi = mid - 1;
}
return -1;
}

int main() {
int a[] = {1, 3, 4, 7, 9, 12, 15, 20};
int n = sizeof(a) / sizeof(a[0]);

for (int i = 0; i < n; ++i) {
int idx = binary_search(a, n, a[i]);
assert(idx == i);
}
assert(binary_search(a, n, 6) == -1);
assert(binary_search(a, n, 0) == -1);
assert(binary_search(a, n, 21) == -1);
}
34 changes: 34 additions & 0 deletions tests/test_cctype.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <cassert>
#include <cctype>
#include <cstddef>

// Caesar cipher (ROT13) built entirely from <cctype> primitives: classify
// letters with isalpha/islower/isupper, then shift within their case.
char rot13(char c) {
if (!std::isalpha(static_cast<unsigned char>(c)))
return c;
char base = std::isupper(static_cast<unsigned char>(c)) ? 'A' : 'a';
return static_cast<char>(base + (c - base + 13) % 26);
}

int main() {
const char* msg = "Hello, World! 123";
char rot[32] = {};
char back[32] = {};
std::size_t n = 0;
for (; msg[n]; ++n) {
rot[n] = rot13(msg[n]);
back[n] = rot13(rot[n]); // applying ROT13 twice recovers the original
}
rot[n] = back[n] = '\0';

for (std::size_t i = 0; i < n; ++i)
assert(back[i] == msg[i]);

assert(rot13('H') == 'U');
assert(rot13('!') == '!');
assert(std::toupper('a') == 'A');
assert(std::tolower('Z') == 'z');
assert(std::isdigit('7') && !std::isdigit('x'));
assert(std::isspace(' ') && !std::isspace('x'));
}
20 changes: 20 additions & 0 deletions tests/test_cerrno.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <cassert>
#include <cerrno>
#include <cstdlib>

int main() {
errno = 0;
double d = std::strtod("1e400", nullptr); // overflows double range
assert(errno == ERANGE);
assert(d > 0);

errno = 0;
long l = std::strtol("not a number", nullptr, 10);
assert(l == 0);
assert(errno == 0); // no conversion is not itself an error

errno = E2BIG; // sanity-check a couple of the standard macros exist
assert(errno == E2BIG);
errno = 0;
assert(errno == 0);
}
Loading