Skip to content

Commit bf916f6

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents bb0f91a + 37f1372 commit bf916f6

36 files changed

Lines changed: 544 additions & 388 deletions

.github/workflows/issue-close.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ jobs:
1313
- uses: actions/stale@v8
1414
with:
1515
any-of-issue-labels: Needs clarification, Answered, Stale?
16-
days-before-issue-stale: 30
16+
days-before-issue-stale: 365
1717
days-before-issue-close: 14
1818
stale-issue-label: Stale
1919
stale-issue-message: |
20-
This issue is stale because it has been open for 30 days with no activity.
20+
This issue is stale because it has been open for 365 days with no activity.
2121
It will be automatically closed in 14 days.
2222
close-issue-message: |
2323
This issue was closed because it has been inactive for 14 days since being marked as stale.

.github/workflows/sanitizers.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
name: Sanitizers
2+
on:
3+
workflow_dispatch:
4+
pull_request:
5+
push:
6+
branches: [master]
7+
concurrency:
8+
group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }}
9+
cancel-in-progress: true
10+
defaults:
11+
run:
12+
shell: bash -e -l {0}
13+
jobs:
14+
build:
15+
runs-on: ${{ matrix.os }}
16+
name: sanitizer / ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} / ${{ matrix.config.name }} / ${{ matrix.sys.name }}
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
os: [ubuntu-24.04]
21+
sys:
22+
- {compiler: clang, version: '21', name: asan, sanitizer: address}
23+
- {compiler: clang, version: '21', name: lsan, sanitizer: leak}
24+
- {compiler: clang, version: '21', name: ubsan, sanitizer: undefined}
25+
config:
26+
- {name: Debug}
27+
28+
steps:
29+
30+
- name: Install LLVM and Clang
31+
if: matrix.sys.compiler == 'clang'
32+
run: |
33+
wget https://apt.llvm.org/llvm.sh
34+
chmod +x llvm.sh
35+
sudo ./llvm.sh ${{matrix.sys.version}}
36+
sudo apt-get install -y clang-tools-${{matrix.sys.version}}
37+
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${{matrix.sys.version}} 200
38+
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{matrix.sys.version}} 200
39+
sudo update-alternatives --install /usr/bin/clang-scan-deps clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} 200
40+
sudo update-alternatives --set clang /usr/bin/clang-${{matrix.sys.version}}
41+
sudo update-alternatives --set clang++ /usr/bin/clang++-${{matrix.sys.version}}
42+
sudo update-alternatives --set clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}}
43+
44+
- name: Checkout code
45+
uses: actions/checkout@v6
46+
47+
- name: Set conda environment
48+
uses: mamba-org/setup-micromamba@main
49+
with:
50+
environment-name: myenv
51+
environment-file: environment-dev.yml
52+
init-shell: bash
53+
cache-downloads: true
54+
55+
- name: Configure using CMake
56+
run: |
57+
export CC=clang
58+
export CXX=clang++
59+
cmake -G Ninja \
60+
-Bbuild \
61+
-DCMAKE_BUILD_TYPE=${{matrix.config.name}} \
62+
-DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \
63+
-DBUILD_TESTS=ON \
64+
-DUSE_SANITIZER=${{ matrix.sys.sanitizer }}
65+
66+
- name: Build tests
67+
working-directory: build
68+
run: cmake --build . --config ${{matrix.config.name}} --target test_xtensor_lib --parallel 8
69+
70+
- name: Run tests
71+
working-directory: build
72+
run: |
73+
SAN=${{ matrix.sys.sanitizer }}
74+
case "$SAN" in
75+
address)
76+
export ASAN_OPTIONS=log_path=asan_log_:alloc_dealloc_mismatch=0:halt_on_error=0:handle_abort=0
77+
export ASAN_SAVE_DUMPS=AsanDump.dmp
78+
;;
79+
leak)
80+
export LSAN_OPTIONS=log_path=lsan_log_:halt_on_error=0
81+
;;
82+
undefined)
83+
export UBSAN_OPTIONS=log_path=ubsan_log_:halt_on_error=0:print_stacktrace=1
84+
;;
85+
esac
86+
ctest -R ^xtest$ --output-on-failure
87+
88+
- name: Upload sanitizer log
89+
if: always()
90+
uses: actions/upload-artifact@v6
91+
with:
92+
name: sanitizer-log-${{ matrix.sys.sanitizer }}-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }}
93+
path: '**/*san_log_*'
94+
if-no-files-found: ignore
95+
96+
- name: Upload sanitizer dump
97+
if: always()
98+
uses: actions/upload-artifact@v6
99+
with:
100+
name: sanitizer-dump-${{ matrix.sys.sanitizer }}-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }}
101+
path: '**/AsanDump.dmp'
102+
if-no-files-found: ignore
103+
104+
- name: Return errors if sanitizer log content is not empty
105+
if: always()
106+
run: |
107+
if [ -n "$(find build/test -name '*san_log_*' -type f -size +0 2>/dev/null)" ]; then
108+
echo "Sanitizer detected errors. See the log for details."
109+
exit 1
110+
fi

cmake/sanitizers.cmake

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
set(AVALAIBLE_SANITIZERS "address;leak;memory;thread;undefined")
2+
OPTION(USE_SANITIZER "Enable sanitizer(s). Options are: ${AVALAIBLE_SANITIZERS}. Case insensitive; multiple options delimited by comma or space possible." "")
3+
string(TOLOWER "${USE_SANITIZER}" USE_SANITIZER)
4+
5+
if((CMAKE_BUILD_TYPE IN_LIST "Debug;RelWithDebInfo") AND USE_SANITIZER)
6+
message(FATAL_ERROR "❌ Sanitizer only supported in Debug and RelWithDebInfo build types.")
7+
endif()
8+
9+
if(USE_SANITIZER)
10+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
11+
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
12+
13+
if(USE_SANITIZER MATCHES "address")
14+
list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION)
15+
else()
16+
message(FATAL_ERROR "❌ Sanitizer not supported by MSVC: ${USE_SANITIZER}. It only supports 'address'.")
17+
endif()
18+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
19+
if(USE_SANITIZER MATCHES "address")
20+
list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION)
21+
list(APPEND SANITIZER_LINK_LIBRARIES clang_rt.asan_dynamic-x86_64 clang_rt.asan_dynamic_runtime_thunk-x86_64)
22+
else()
23+
message(FATAL_ERROR "❌ Sanitizer not supported by Clang-MSVC: ${USE_SANITIZER}. It only supports 'address'.")
24+
endif()
25+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
26+
foreach(sanitizer ${USE_SANITIZER})
27+
if(NOT ${sanitizer} IN_LIST AVALAIBLE_SANITIZERS)
28+
message(FATAL_ERROR "❌ Sanitizer not supported: ${sanitizer}. It should be one of: ${AVALAIBLE_SANITIZERS}.")
29+
endif()
30+
list(APPEND SANITIZER_COMPILE_OPTIONS -fsanitize=${sanitizer})
31+
list(APPEND SANITIZER_LINK_OPTIONS -fsanitize=${sanitizer})
32+
if (${sanitizer} MATCHES "undefined")
33+
list(APPEND SANITIZER_COMPILE_OPTIONS -fno-sanitize=signed-integer-overflow)
34+
endif()
35+
if (${sanitizer} MATCHES "memory")
36+
list(APPEND SANITIZER_LINK_LIBRARIES -fsanitize-memory-track-origins -fPIE -pie)
37+
list(APPEND SANITIZER_LINK_OPTIONS -fsanitize-memory-track-origins -fPIE -pie)
38+
endif()
39+
endforeach()
40+
list(APPEND SANITIZER_COMPILE_OPTIONS -fno-omit-frame-pointer)
41+
else()
42+
message(FATAL_ERROR "❌ Sanitizer: Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}")
43+
endif()
44+
45+
list(REMOVE_DUPLICATES SANITIZER_COMPILE_OPTIONS)
46+
list(REMOVE_DUPLICATES SANITIZER_LINK_OPTIONS)
47+
list(REMOVE_DUPLICATES SANITIZER_LINK_LIBRARIES)
48+
49+
message(STATUS "🔍 Using sanitizer: ${USE_SANITIZER}")
50+
endif()

include/xtensor/core/xassign.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ namespace xt
214214
template <class E1, class E2>
215215
inline void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2)
216216
{
217-
if constexpr (has_assign_to<E1, E2>::value)
217+
if constexpr (assignable_to_expression<E1, E2>)
218218
{
219219
e2.derived_cast().assign_to(e1);
220220
}
@@ -267,14 +267,14 @@ namespace xt
267267

268268
template <class E1, class E2>
269269
inline auto is_linear_assign(const E1& e1, const E2& e2)
270-
-> std::enable_if_t<has_strides<E1>::value, bool>
270+
-> std::enable_if_t<strided_expression<E1>, bool>
271271
{
272272
return (E1::contiguous_layout && E2::contiguous_layout && linear_static_layout<E1, E2>())
273273
|| (e1.is_contiguous() && e2.has_linear_assign(e1.strides()));
274274
}
275275

276276
template <class E1, class E2>
277-
inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t<!has_strides<E1>::value, bool>
277+
inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t<!strided_expression<E1>, bool>
278278
{
279279
return false;
280280
}
@@ -304,7 +304,7 @@ namespace xt
304304
return std::is_reference<typename T::stepper::reference>::value;
305305
}
306306

307-
static constexpr bool value = has_strides<T>::value
307+
static constexpr bool value = strided_expression<T>
308308
&& has_step_leading<typename T::stepper>::value && stepper_deref();
309309
};
310310

@@ -1002,13 +1002,13 @@ namespace xt
10021002
const strides_type& m_strides;
10031003
};
10041004

1005-
template <bool possible = true, class E1, class E2, std::enable_if_t<!has_strides<E1>::value || !possible, bool> = true>
1005+
template <bool possible = true, class E1, class E2, std::enable_if_t<!strided_expression<E1> || !possible, bool> = true>
10061006
loop_sizes_t get_loop_sizes(const E1& e1, const E2&)
10071007
{
10081008
return {false, true, 1, e1.size(), e1.dimension(), e1.dimension()};
10091009
}
10101010

1011-
template <bool possible = true, class E1, class E2, std::enable_if_t<has_strides<E1>::value && possible, bool> = true>
1011+
template <bool possible = true, class E1, class E2, std::enable_if_t<strided_expression<E1> && possible, bool> = true>
10121012
loop_sizes_t get_loop_sizes(const E1& e1, const E2& e2)
10131013
{
10141014
using shape_value_type = typename E1::shape_type::value_type;

include/xtensor/core/xeval.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,15 @@ namespace xt
147147
*/
148148
template <layout_type L = layout_type::any, class E>
149149
inline auto as_strided(E&& e)
150-
-> std::enable_if_t<has_data_interface<std::decay_t<E>>::value && detail::has_same_layout<L, E>(), E&&>
150+
-> std::enable_if_t<data_interface_expression<std::decay_t<E>> && detail::has_same_layout<L, E>(), E&&>
151151
{
152152
return std::forward<E>(e);
153153
}
154154

155155
/// @cond DOXYGEN_INCLUDE_SFINAE
156156
template <layout_type L = layout_type::any, class E>
157157
inline auto as_strided(E&& e) -> std::enable_if_t<
158-
(!(has_data_interface<std::decay_t<E>>::value && detail::has_same_layout<L, E>()))
158+
(!(data_interface_expression<std::decay_t<E>> && detail::has_same_layout<L, E>()))
159159
&& detail::has_fixed_dims<E>(),
160160
detail::as_xtensor_container_t<E, L>>
161161
{
@@ -164,7 +164,7 @@ namespace xt
164164

165165
template <layout_type L = layout_type::any, class E>
166166
inline auto as_strided(E&& e) -> std::enable_if_t<
167-
(!(has_data_interface<std::decay_t<E>>::value && detail::has_same_layout<L, E>()))
167+
(!(data_interface_expression<std::decay_t<E>> && detail::has_same_layout<L, E>()))
168168
&& (!detail::has_fixed_dims<E>()),
169169
detail::as_xarray_container_t<E, L>>
170170
{

include/xtensor/core/xexpression.hpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -525,15 +525,18 @@ namespace xt
525525
using inner_shape_type = typename E::inner_shape_type;
526526
using shape_type = typename E::shape_type;
527527

528-
using strides_type = xtl::mpl::
529-
eval_if_t<has_strides<E>, detail::expr_strides_type<E>, get_strides_type<shape_type>>;
530-
using backstrides_type = xtl::mpl::
531-
eval_if_t<has_strides<E>, detail::expr_backstrides_type<E>, get_strides_type<shape_type>>;
532-
using inner_strides_type = xtl::mpl::
533-
eval_if_t<has_strides<E>, detail::expr_inner_strides_type<E>, get_strides_type<shape_type>>;
534-
using inner_backstrides_type = xtl::mpl::
535-
eval_if_t<has_strides<E>, detail::expr_inner_backstrides_type<E>, get_strides_type<shape_type>>;
536-
using storage_type = xtl::mpl::eval_if_t<has_storage_type<E>, detail::expr_storage_type<E>, make_invalid_type<>>;
528+
using strides_type = typename std::
529+
conditional_t<strided_expression<E>, detail::expr_strides_type<E>, get_strides_type<shape_type>>::type;
530+
using backstrides_type = typename std::
531+
conditional_t<strided_expression<E>, detail::expr_backstrides_type<E>, get_strides_type<shape_type>>::type;
532+
using inner_strides_type = typename std::
533+
conditional_t<strided_expression<E>, detail::expr_inner_strides_type<E>, get_strides_type<shape_type>>::type;
534+
using inner_backstrides_type = typename std::conditional_t<
535+
strided_expression<E>,
536+
detail::expr_inner_backstrides_type<E>,
537+
get_strides_type<shape_type>>::type;
538+
using storage_type = typename std::
539+
conditional_t<container_expression<E>, detail::expr_storage_type<E>, make_invalid_type<>>::type;
537540

538541
using stepper = typename E::stepper;
539542
using const_stepper = typename E::const_stepper;
@@ -638,43 +641,43 @@ namespace xt
638641
}
639642

640643
template <class T = E>
641-
std::enable_if_t<has_strides<T>::value, const inner_strides_type&> strides() const
644+
std::enable_if_t<strided_expression<T>, const inner_strides_type&> strides() const
642645
{
643646
return m_ptr->strides();
644647
}
645648

646649
template <class T = E>
647-
std::enable_if_t<has_strides<T>::value, const inner_strides_type&> backstrides() const
650+
std::enable_if_t<strided_expression<T>, const inner_strides_type&> backstrides() const
648651
{
649652
return m_ptr->backstrides();
650653
}
651654

652655
template <class T = E>
653-
std::enable_if_t<has_data_interface<T>::value, pointer> data() noexcept
656+
std::enable_if_t<data_interface_expression<T>, pointer> data() noexcept
654657
{
655658
return m_ptr->data();
656659
}
657660

658661
template <class T = E>
659-
std::enable_if_t<has_data_interface<T>::value, pointer> data() const noexcept
662+
std::enable_if_t<data_interface_expression<T>, pointer> data() const noexcept
660663
{
661664
return m_ptr->data();
662665
}
663666

664667
template <class T = E>
665-
std::enable_if_t<has_data_interface<T>::value, size_type> data_offset() const noexcept
668+
std::enable_if_t<data_interface_expression<T>, size_type> data_offset() const noexcept
666669
{
667670
return m_ptr->data_offset();
668671
}
669672

670673
template <class T = E>
671-
std::enable_if_t<has_data_interface<T>::value, typename T::storage_type&> storage() noexcept
674+
std::enable_if_t<data_interface_expression<T>, typename T::storage_type&> storage() noexcept
672675
{
673676
return m_ptr->storage();
674677
}
675678

676679
template <class T = E>
677-
std::enable_if_t<has_data_interface<T>::value, const typename T::storage_type&> storage() const noexcept
680+
std::enable_if_t<data_interface_expression<T>, const typename T::storage_type&> storage() const noexcept
678681
{
679682
return m_ptr->storage();
680683
}

include/xtensor/core/xfunction.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ namespace xt
133133
struct xcontainer_inner_types<xfunction<F, CT...>>
134134
{
135135
// Added indirection for MSVC 2017 bug with the operator value_type()
136-
using func_return_type = typename meta_identity<
136+
using func_return_type = typename std::type_identity<
137137
decltype(std::declval<F>()(std::declval<xvalue_type_t<std::decay_t<CT>>>()...))>::type;
138138
using value_type = std::decay_t<func_return_type>;
139139
using reference = func_return_type;
@@ -156,7 +156,7 @@ namespace xt
156156
template <class E>
157157
struct overlapping_memory_checker_traits<
158158
E,
159-
std::enable_if_t<!has_memory_address<E>::value && is_specialization_of<xfunction, E>::value>>
159+
std::enable_if_t<!addressable_to_expression<E> && is_specialization_of<xfunction, E>::value>>
160160
{
161161
template <std::size_t I = 0, class... T, std::enable_if_t<(I == sizeof...(T)), int> = 0>
162162
static bool check_tuple(const std::tuple<T...>&, const memory_range&)

include/xtensor/core/xiterable.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ namespace xt
293293
};
294294

295295
template <class D>
296-
using linear_iterator_traits = linear_iterator_traits_impl<D, has_storage_type<D>::value>;
296+
using linear_iterator_traits = linear_iterator_traits_impl<D, container_expression<D>>;
297297
}
298298

299299
/**

include/xtensor/core/xmath.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,13 @@ namespace xt
350350
namespace detail
351351
{
352352
template <class R, class T>
353-
std::enable_if_t<!has_iterator_interface<R>::value, R> fill_init(T init)
353+
std::enable_if_t<!iterable_expression<R>, R> fill_init(T init)
354354
{
355355
return R(init);
356356
}
357357

358358
template <class R, class T>
359-
std::enable_if_t<has_iterator_interface<R>::value, R> fill_init(T init)
359+
std::enable_if_t<iterable_expression<R>, R> fill_init(T init)
360360
{
361361
R result;
362362
std::fill(std::begin(result), std::end(result), init);

include/xtensor/core/xsemantic.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ namespace xt
224224
template <class E>
225225
struct overlapping_memory_checker_traits<
226226
E,
227-
std::enable_if_t<!has_memory_address<E>::value && is_crtp_base_of<xview_semantic, E>::value>>
227+
std::enable_if_t<!addressable_to_expression<E> && is_crtp_base_of<xview_semantic, E>::value>>
228228
{
229229
static bool check_overlap(const E& expr, const memory_range& dst_range)
230230
{

0 commit comments

Comments
 (0)