Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .github/workflows/update-status-chart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
schedule:
- cron: "0 7 * * *"
workflow_dispatch:
permissions:
contents: write
jobs:
build:
if: ${{ github.repository == 'microsoft/STL' }}
Expand Down
4 changes: 4 additions & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ endif()

set(CMAKE_BUILD_TYPE RelWithDebInfo)

# /utf-8 affects <format>.
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/diagnostics:caret;/W4;/WX;/w14265;/w15038;/w15262;/utf-8>")

if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/google-benchmark/.git")
message(FATAL_ERROR "google-benchmark is not checked out; make sure to run\n git submodule update --init benchmarks/google-benchmark")
endif()
Expand Down Expand Up @@ -107,6 +110,7 @@ endfunction()

add_benchmark(bitset_to_string src/bitset_to_string.cpp)
add_benchmark(locale_classic src/locale_classic.cpp)
add_benchmark(minmax_element src/minmax_element.cpp)
add_benchmark(path_lexically_normal src/path_lexically_normal.cpp)
add_benchmark(priority_queue_push_range src/priority_queue_push_range.cpp)
add_benchmark(random_integer_generation src/random_integer_generation.cpp)
Expand Down
10 changes: 5 additions & 5 deletions benchmarks/inc/udt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

#pragma once

template <typename Contained>
template <typename Data>
struct aggregate {
Contained c;
Data c;

friend bool operator==(const aggregate&, const aggregate&) = default;
};

template <typename Contained>
template <typename Data>
struct non_trivial {
Contained c;
Data c;
non_trivial() : c() {}
non_trivial(const Contained& src) : c(src) {}
non_trivial(const Data& src) : c(src) {}
non_trivial(const non_trivial& other) : c(other.c) {}
non_trivial& operator=(const non_trivial& other) {
c = other.c;
Expand Down
9 changes: 9 additions & 0 deletions benchmarks/inc/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ std::vector<Contained> random_vector(size_t n) {
xoshiro256ss prng{id64(rd), id64(rd), id64(rd), id64(rd)};

std::vector<Contained> res(n);

// Here, the type Contained can be char, int, aggregate<Data>, or non_trivial<Data> where Data is char or int.
// (aggregate<Data> and non_trivial<Data> are defined in udt.hpp.)
// static_cast<Contained> silences truncation warnings when Contained is directly char or int,
// but is insufficient for aggregate<Data> or non_trivial<Data>.
#pragma warning(push)
#pragma warning(disable : 4244) // warning C4244: conversion from 'uint64_t' to 'Data', possible loss of data
std::generate(res.begin(), res.end(), [&prng] { return static_cast<Contained>(prng.next()); });
#pragma warning(pop)

return res;
}
86 changes: 86 additions & 0 deletions benchmarks/src/minmax_element.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <benchmark/benchmark.h>
#include <cstddef>
#include <cstdint>
#include <random>
#include <ranges>
#include <type_traits>

enum class Op {
Min,
Max,
Both,
};

using namespace std;

template <class T, size_t Size, Op Operation>
void bm(benchmark::State& state) {
T a[Size];

mt19937 gen(84710);

if constexpr (is_floating_point_v<T>) {
normal_distribution<T> dis(0, 10000.0);
ranges::generate(a, [&] { return dis(gen); });
} else {
uniform_int_distribution<conditional_t<sizeof(T) != 1, T, int>> dis(1, 20);
ranges::generate(a, [&] { return static_cast<T>(dis(gen)); });
}

for (auto _ : state) {
if constexpr (Operation == Op::Min) {
benchmark::DoNotOptimize(ranges::min_element(a));
} else if constexpr (Operation == Op::Max) {
benchmark::DoNotOptimize(ranges::max_element(a));
} else if constexpr (Operation == Op::Both) {
benchmark::DoNotOptimize(ranges::minmax_element(a));
}
}
}

BENCHMARK(bm<uint8_t, 8021, Op::Min>);
BENCHMARK(bm<uint8_t, 8021, Op::Max>);
BENCHMARK(bm<uint8_t, 8021, Op::Both>);

BENCHMARK(bm<uint16_t, 8021, Op::Min>);
BENCHMARK(bm<uint16_t, 8021, Op::Max>);
BENCHMARK(bm<uint16_t, 8021, Op::Both>);

BENCHMARK(bm<uint32_t, 8021, Op::Min>);
BENCHMARK(bm<uint32_t, 8021, Op::Max>);
BENCHMARK(bm<uint32_t, 8021, Op::Both>);

BENCHMARK(bm<uint64_t, 8021, Op::Min>);
BENCHMARK(bm<uint64_t, 8021, Op::Max>);
BENCHMARK(bm<uint64_t, 8021, Op::Both>);

BENCHMARK(bm<int8_t, 8021, Op::Min>);
BENCHMARK(bm<int8_t, 8021, Op::Max>);
BENCHMARK(bm<int8_t, 8021, Op::Both>);

BENCHMARK(bm<int16_t, 8021, Op::Min>);
BENCHMARK(bm<int16_t, 8021, Op::Max>);
BENCHMARK(bm<int16_t, 8021, Op::Both>);

BENCHMARK(bm<int32_t, 8021, Op::Min>);
BENCHMARK(bm<int32_t, 8021, Op::Max>);
BENCHMARK(bm<int32_t, 8021, Op::Both>);

BENCHMARK(bm<int64_t, 8021, Op::Min>);
BENCHMARK(bm<int64_t, 8021, Op::Max>);
BENCHMARK(bm<int64_t, 8021, Op::Both>);

BENCHMARK(bm<float, 8021, Op::Min>);
BENCHMARK(bm<float, 8021, Op::Max>);
BENCHMARK(bm<float, 8021, Op::Both>);

BENCHMARK(bm<double, 8021, Op::Min>);
BENCHMARK(bm<double, 8021, Op::Max>);
BENCHMARK(bm<double, 8021, Op::Both>);


BENCHMARK_MAIN();
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <benchmark/benchmark.h>
//
#include <algorithm>
#include <cstddef>
#include <random>
#include <vector>

Expand All @@ -17,7 +18,7 @@ static vector<bool> createRandomVector(const size_t size) {
}

static void copy_block_aligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -27,7 +28,7 @@ static void copy_block_aligned(benchmark::State& state) {
}

static void copy_source_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -37,7 +38,7 @@ static void copy_source_misaligned(benchmark::State& state) {
}

static void copy_dest_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -48,7 +49,7 @@ static void copy_dest_misaligned(benchmark::State& state) {

// Special benchmark for matching char alignment
static void copy_matching_alignment(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <benchmark/benchmark.h>
//
#include <algorithm>
#include <cstddef>
#include <random>
#include <vector>

Expand All @@ -17,7 +18,7 @@ static vector<bool> createRandomVector(const size_t size) {
}

static void copy_n_block_aligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -27,7 +28,7 @@ static void copy_n_block_aligned(benchmark::State& state) {
}

static void copy_n_source_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -37,7 +38,7 @@ static void copy_n_source_misaligned(benchmark::State& state) {
}

static void copy_n_dest_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -48,7 +49,7 @@ static void copy_n_dest_misaligned(benchmark::State& state) {

// Special benchmark for matching char alignment
static void copy_n_matching_alignment(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <benchmark/benchmark.h>
//
#include <algorithm>
#include <cstddef>
#include <random>
#include <vector>

Expand All @@ -17,7 +18,7 @@ static vector<bool> createRandomVector(const size_t size) {
}

static void move_block_aligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -27,7 +28,7 @@ static void move_block_aligned(benchmark::State& state) {
}

static void move_source_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -37,7 +38,7 @@ static void move_source_misaligned(benchmark::State& state) {
}

static void move_dest_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand All @@ -48,7 +49,7 @@ static void move_dest_misaligned(benchmark::State& state) {

// Special benchmark for matching char alignment
static void move_matching_alignment(benchmark::State& state) {
const auto size = state.range(0);
const auto size = static_cast<size_t>(state.range(0));
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

Expand Down
18 changes: 9 additions & 9 deletions stl/inc/__msvc_bit_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ _NODISCARD int _Checked_arm_arm64_countl_zero(const _Ty _Val) noexcept {
} else {
return static_cast<int>(_CountLeadingZeros64(_Val));
}
#endif // TRANSITION, GH-1586
#endif // ^^^ no workaround ^^^
}
#endif // defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64)
#endif // _HAS_COUNTL_ZERO_INTRINSICS
Expand Down Expand Up @@ -376,19 +376,19 @@ constexpr decltype(auto) _Select_countr_zero_impl(_Fn _Callback) {
#if _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20
if (!_STD is_constant_evaluated()) {
#ifdef __AVX2__
return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_tzcnt(_Val); });
#else // ^^^ AVX2 / not AVX2 vvv
const bool _Definitely_have_tzcnt = __isa_available >= _Stl_isa_available_avx2;
if (_Definitely_have_tzcnt) {
return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_tzcnt(_Val); });
} else {
return _Callback([](_Ty _Val) { return _Countr_zero_bsf(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_bsf(_Val); });
}
#endif // ^^^ not AVX2 ^^^
}
#endif // ^^^ _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 ^^^
// C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation.
return _Callback([](_Ty _Val) { return _Countr_zero_fallback(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_fallback(_Val); });
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
Expand Down Expand Up @@ -420,16 +420,16 @@ _CONSTEXPR20 decltype(auto) _Select_popcount_impl(_Fn _Callback) {
#ifndef __AVX__
const bool _Definitely_have_popcnt = __isa_available >= _Stl_isa_available_sse42;
if (!_Definitely_have_popcnt) {
return _Callback([](_Ty _Val) { return _Popcount_fallback(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); });
}
#endif // !defined(__AVX__)
return _Callback([](_Ty _Val) { return _Unchecked_x86_x64_popcount(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Unchecked_x86_x64_popcount(_Val); });
#elif _HAS_NEON_INTRINSICS // ^^^ x86/x64 intrinsics available / ARM64 intrinsics available vvv
return _Callback([](_Ty _Val) { return _Arm64_popcount(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Arm64_popcount(_Val); });
#endif // ^^^ ARM64 intrinsics available ^^^
}
#endif // ^^^ any intrinsics available ^^^
return _Callback([](_Ty _Val) { return _Popcount_fallback(_Val); });
return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); });
}

#undef _HAS_POPCNT_INTRINSICS
Expand Down
8 changes: 4 additions & 4 deletions stl/inc/__msvc_chrono.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ namespace chrono {
return !(_Left < _Right);
}

#ifdef __cpp_lib_concepts
#if _HAS_CXX20
_EXPORT_STD template <class _Rep1, class _Period1, class _Rep2, class _Period2>
requires three_way_comparable<typename common_type_t<duration<_Rep1, _Period1>, duration<_Rep2, _Period2>>::rep>
_NODISCARD constexpr auto operator<=>(const duration<_Rep1, _Period1>& _Left,
Expand All @@ -414,7 +414,7 @@ namespace chrono {
using _CT = common_type_t<duration<_Rep1, _Period1>, duration<_Rep2, _Period2>>;
return _CT(_Left).count() <=> _CT(_Right).count();
}
#endif // defined(__cpp_lib_concepts)
#endif // _HAS_CXX20

_EXPORT_STD template <class _To, class _Rep, class _Period, enable_if_t<_Is_duration_v<_To>, int> /* = 0 */>
_NODISCARD constexpr _To duration_cast(const duration<_Rep, _Period>& _Dur) noexcept(
Expand Down Expand Up @@ -593,14 +593,14 @@ namespace chrono {
return !(_Left < _Right);
}

#ifdef __cpp_lib_concepts
#if _HAS_CXX20
_EXPORT_STD template <class _Clock, class _Duration1, three_way_comparable_with<_Duration1> _Duration2>
_NODISCARD constexpr auto
operator<=>(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept(
is_arithmetic_v<typename _Duration1::rep> && is_arithmetic_v<typename _Duration2::rep>) /* strengthened */ {
return _Left.time_since_epoch() <=> _Right.time_since_epoch();
}
#endif // defined(__cpp_lib_concepts)
#endif // _HAS_CXX20

_EXPORT_STD template <class _To, class _Clock, class _Duration, enable_if_t<_Is_duration_v<_To>, int> = 0>
_NODISCARD constexpr time_point<_Clock, _To> time_point_cast(const time_point<_Clock, _Duration>& _Time) noexcept(
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/__msvc_filebuf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ class basic_filebuf : public basic_streambuf<_Elem, _Traits> { // stream buffer
}
}

#if defined(__cpp_lib_print) && defined(_CPPRTTI)
#if _HAS_CXX23 && defined(_CPPRTTI)
template <class _Filebuf_type>
friend ios_base::iostate _Print_noformat_unicode(ostream&, string_view);
#endif
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/__msvc_formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR

#if !_HAS_CXX20 || !defined(__cpp_lib_concepts) // TRANSITION, GH-395
#if !_HAS_CXX20
#error The contents of <format> are only available with C++20. (Also, you should not include this internal header.)
#endif // !_HAS_CXX20 || !defined(__cpp_lib_concepts)
#endif // !_HAS_CXX20

#include <concepts>
#include <cstddef>
Expand Down
Loading