silly
parent
1830a3936b
commit
0e5d8b6043
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
include(cmake/color.cmake)
|
include(cmake/color.cmake)
|
||||||
set(BLT_VERSION 1.0.6)
|
set(BLT_VERSION 1.1.1)
|
||||||
|
|
||||||
set(BLT_TARGET BLT)
|
set(BLT_TARGET BLT)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Brett Terpstra
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BLT_ITERATOR_ITER_COMMON
|
||||||
|
#define BLT_ITERATOR_ITER_COMMON
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace blt::iterator
|
||||||
|
{
|
||||||
|
template<typename Derived>
|
||||||
|
struct wrapper_base
|
||||||
|
{
|
||||||
|
wrapper_base operator++(int)
|
||||||
|
{
|
||||||
|
auto tmp = *this;
|
||||||
|
++*this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper_base operator--(int)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::bidirectional_iterator_tag> ||
|
||||||
|
std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
auto tmp = *this;
|
||||||
|
--*this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator[](blt::ptrdiff_t n) const
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
return *(*this + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend wrapper_base operator+(const wrapper_base& a, blt::ptrdiff_t n)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
auto copy = a;
|
||||||
|
copy += n;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend wrapper_base operator+(blt::ptrdiff_t n, const wrapper_base& a)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
auto copy = a;
|
||||||
|
copy += n;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend wrapper_base operator-(const wrapper_base& a, blt::ptrdiff_t n)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
auto copy = a;
|
||||||
|
copy -= n;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend wrapper_base operator-(blt::ptrdiff_t n, const wrapper_base& a)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
auto copy = a;
|
||||||
|
copy -= n;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<(const wrapper_base& a, const wrapper_base& b)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
return b - a > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator>(const wrapper_base& a, const wrapper_base& b)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
return b < a;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator>=(const wrapper_base& a, wrapper_base& b)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
return !(a < b); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<=(const wrapper_base& a, const wrapper_base& b)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
|
||||||
|
"Iterator must allow random access");
|
||||||
|
return !(a > b); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const wrapper_base& a, const wrapper_base& b)
|
||||||
|
{
|
||||||
|
return a.base() == b.base();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const wrapper_base& a, const wrapper_base& b)
|
||||||
|
{
|
||||||
|
return !(a.base() == b.base()); // NOLINT
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //BLT_ITERATOR_ITER_COMMON
|
|
@ -1,30 +0,0 @@
|
||||||
#pragma once
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Brett Terpstra
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BLT_ITERATOR_ITER_COMMON
|
|
||||||
#define BLT_ITERATOR_ITER_COMMON
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
namespace blt
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //BLT_ITERATOR_ITER_COMMON
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include <blt/std/types.h>
|
#include <blt/std/types.h>
|
||||||
#include <blt/std/logging.h>
|
#include <blt/std/logging.h>
|
||||||
#include <blt/iterator/iter_common.h>
|
#include <blt/iterator/common.h>
|
||||||
#include <blt/iterator/zip.h>
|
#include <blt/iterator/zip.h>
|
||||||
#include <blt/meta/meta.h>
|
#include <blt/meta/meta.h>
|
||||||
#include <blt/meta/iterator.h>
|
#include <blt/meta/iterator.h>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#ifndef BLT_ITERATOR_ZIP
|
#ifndef BLT_ITERATOR_ZIP
|
||||||
#define BLT_ITERATOR_ZIP
|
#define BLT_ITERATOR_ZIP
|
||||||
|
|
||||||
#include <blt/iterator/iter_common.h>
|
#include <blt/iterator/common.h>
|
||||||
#include <blt/meta/meta.h>
|
#include <blt/meta/meta.h>
|
||||||
#include <blt/meta/iterator.h>
|
#include <blt/meta/iterator.h>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
@ -28,14 +28,11 @@ namespace blt
|
||||||
{
|
{
|
||||||
namespace iterator
|
namespace iterator
|
||||||
{
|
{
|
||||||
template<typename Tag, typename... Iter>
|
|
||||||
class zip_wrapper;
|
|
||||||
|
|
||||||
template<typename... Iter>
|
template<typename... Iter>
|
||||||
class zip_wrapper<std::input_iterator_tag, Iter...>
|
class zip_wrapper : public wrapper_base<zip_wrapper<Iter...>>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using iterator_category = std::input_iterator_tag;
|
using iterator_category = meta::lowest_iterator_category_t<Iter...>;
|
||||||
using value_type = std::tuple<meta::deref_return_t<Iter>...>;
|
using value_type = std::tuple<meta::deref_return_t<Iter>...>;
|
||||||
using difference_type = blt::ptrdiff_t;
|
using difference_type = blt::ptrdiff_t;
|
||||||
using pointer = value_type;
|
using pointer = value_type;
|
||||||
|
@ -49,99 +46,18 @@ namespace blt
|
||||||
return std::apply([](auto& ... i) { return std::tuple<meta::deref_return_t<Iter>...>{*i...}; }, iter);
|
return std::apply([](auto& ... i) { return std::tuple<meta::deref_return_t<Iter>...>{*i...}; }, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(const zip_wrapper& a, const zip_wrapper& b)
|
|
||||||
{
|
|
||||||
return a.iter == b.iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const zip_wrapper& a, const zip_wrapper& b)
|
|
||||||
{
|
|
||||||
return !(a.iter == b.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
zip_wrapper& operator++()
|
zip_wrapper& operator++()
|
||||||
{
|
{
|
||||||
std::apply([](auto& ... i) { ((++i), ...); }, iter);
|
std::apply([](auto& ... i) { ((++i), ...); }, iter);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_wrapper operator++(int)
|
|
||||||
{
|
|
||||||
auto tmp = *this;
|
|
||||||
++*this;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto raw_tuple()
|
|
||||||
{
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::tuple<Iter...> iter;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Iter>
|
|
||||||
class zip_wrapper<std::forward_iterator_tag, Iter...> : public zip_wrapper<std::input_iterator_tag, Iter...>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using iterator_category = std::forward_iterator_tag;
|
|
||||||
using value_type = std::tuple<meta::deref_return_t<Iter>...>;
|
|
||||||
using difference_type = blt::ptrdiff_t;
|
|
||||||
using pointer = value_type;
|
|
||||||
using reference = value_type;
|
|
||||||
|
|
||||||
using zip_wrapper<std::input_iterator_tag, Iter...>::zip_wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Iter>
|
|
||||||
class zip_wrapper<std::bidirectional_iterator_tag, Iter...> : public zip_wrapper<std::forward_iterator_tag, Iter...>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
|
||||||
using value_type = std::tuple<meta::deref_return_t<Iter>...>;
|
|
||||||
using difference_type = blt::ptrdiff_t;
|
|
||||||
using pointer = value_type;
|
|
||||||
using reference = value_type;
|
|
||||||
public:
|
|
||||||
using zip_wrapper<std::forward_iterator_tag, Iter...>::zip_wrapper;
|
|
||||||
|
|
||||||
zip_wrapper& operator--()
|
zip_wrapper& operator--()
|
||||||
{
|
{
|
||||||
std::apply([](auto& ... i) { ((--i), ...); }, this->iter);
|
std::apply([](auto& ... i) { ((--i), ...); }, this->iter);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_wrapper operator--(int)
|
|
||||||
{
|
|
||||||
auto tmp = *this;
|
|
||||||
--*this;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Iter>
|
|
||||||
class zip_wrapper<std::random_access_iterator_tag, Iter...> : public zip_wrapper<std::bidirectional_iterator_tag, Iter...>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using iterator_category = std::random_access_iterator_tag;
|
|
||||||
using value_type = std::tuple<meta::deref_return_t<Iter>...>;
|
|
||||||
using difference_type = blt::ptrdiff_t;
|
|
||||||
using pointer = value_type;
|
|
||||||
using reference = value_type;
|
|
||||||
private:
|
|
||||||
template<typename T, T... n>
|
|
||||||
static blt::ptrdiff_t sub(const zip_wrapper& a, const zip_wrapper& b,
|
|
||||||
std::integer_sequence<T, n...>)
|
|
||||||
{
|
|
||||||
blt::ptrdiff_t min = std::numeric_limits<blt::ptrdiff_t>::max();
|
|
||||||
((min = std::min(min, std::get<n>(a.iter) - std::get<n>(b.iter))), ...);
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using zip_wrapper<std::bidirectional_iterator_tag, Iter...>::zip_wrapper;
|
|
||||||
|
|
||||||
zip_wrapper& operator+=(blt::ptrdiff_t n)
|
zip_wrapper& operator+=(blt::ptrdiff_t n)
|
||||||
{
|
{
|
||||||
std::apply([n](auto& ... i) { ((i += n), ...); }, this->iter);
|
std::apply([n](auto& ... i) { ((i += n), ...); }, this->iter);
|
||||||
|
@ -154,54 +70,26 @@ namespace blt
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend zip_wrapper operator+(const zip_wrapper& a, blt::ptrdiff_t n)
|
|
||||||
{
|
|
||||||
return std::apply([n](auto& ... i) { return zip_wrapper{(i + n)...}; }, a.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend zip_wrapper operator+(blt::ptrdiff_t n, const zip_wrapper& a)
|
|
||||||
{
|
|
||||||
return std::apply([n](auto& ... i) { return zip_wrapper{(i + n)...}; }, a.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend zip_wrapper operator-(const zip_wrapper& a, blt::ptrdiff_t n)
|
|
||||||
{
|
|
||||||
return std::apply([n](auto& ... i) { return zip_wrapper{(i - n)...}; }, a.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend zip_wrapper operator-(blt::ptrdiff_t n, const zip_wrapper& a)
|
|
||||||
{
|
|
||||||
return std::apply([n](auto& ... i) { return zip_wrapper{(i - n)...}; }, a.iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend blt::ptrdiff_t operator-(const zip_wrapper& a, const zip_wrapper& b)
|
friend blt::ptrdiff_t operator-(const zip_wrapper& a, const zip_wrapper& b)
|
||||||
{
|
{
|
||||||
return sub(a, b, std::index_sequence_for<Iter...>());
|
return sub(a, b, std::index_sequence_for<Iter...>());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator[](blt::ptrdiff_t n) const
|
auto base()
|
||||||
{
|
{
|
||||||
return *(*this + n);
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::tuple<Iter...> iter;
|
||||||
|
|
||||||
friend bool operator<(const zip_wrapper& a, const zip_wrapper& b)
|
template<typename T, T... n>
|
||||||
|
static blt::ptrdiff_t sub(const zip_wrapper& a, const zip_wrapper& b,
|
||||||
|
std::integer_sequence<T, n...>)
|
||||||
{
|
{
|
||||||
return b - a > 0;
|
blt::ptrdiff_t min = std::numeric_limits<blt::ptrdiff_t>::max();
|
||||||
}
|
((min = std::min(min, std::get<n>(a.iter) - std::get<n>(b.iter))), ...);
|
||||||
|
return min;
|
||||||
friend bool operator>(const zip_wrapper& a, const zip_wrapper& b)
|
|
||||||
{
|
|
||||||
return b < a;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator>=(const zip_wrapper& a, const zip_wrapper& b)
|
|
||||||
{
|
|
||||||
return !(a < b); // NOLINT
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator<=(const zip_wrapper& a, const zip_wrapper& b)
|
|
||||||
{
|
|
||||||
return !(a > b); // NOLINT
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -294,7 +182,8 @@ namespace blt
|
||||||
{
|
{
|
||||||
for (blt::size_t i = 0; i < n; i++)
|
for (blt::size_t i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
if constexpr (check){
|
if constexpr (check)
|
||||||
|
{
|
||||||
if (begin == end)
|
if (begin == end)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -341,7 +230,7 @@ namespace blt
|
||||||
m_begins(std::move(iterator_pairs.begin)...), m_ends(std::move(iterator_pairs.end)...)
|
m_begins(std::move(iterator_pairs.begin)...), m_ends(std::move(iterator_pairs.end)...)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
zip_iterator_storage(iterator::zip_wrapper<iterator_category, Iter...> begins, iterator::zip_wrapper<iterator_category, Iter...> ends):
|
zip_iterator_storage(iterator::zip_wrapper<Iter...> begins, iterator::zip_wrapper<Iter...> ends):
|
||||||
m_begins(std::move(begins)), m_ends(std::move(ends))
|
m_begins(std::move(begins)), m_ends(std::move(ends))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -372,8 +261,8 @@ namespace blt
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iterator::zip_wrapper<iterator_category, Iter...> m_begins;
|
iterator::zip_wrapper<Iter...> m_begins;
|
||||||
iterator::zip_wrapper<iterator_category, Iter...> m_ends;
|
iterator::zip_wrapper<Iter...> m_ends;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Iter>
|
template<typename... Iter>
|
||||||
|
@ -389,8 +278,8 @@ namespace blt
|
||||||
"reverse iteration is only supported on bidirectional or better iterators!");
|
"reverse iteration is only supported on bidirectional or better iterators!");
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_iterator_storage_rev(iterator::zip_wrapper<iterator_category, Iter...> begins,
|
zip_iterator_storage_rev(iterator::zip_wrapper<Iter...> begins,
|
||||||
iterator::zip_wrapper<iterator_category, Iter...> ends): m_begins(std::move(begins)), m_ends(std::move(ends))
|
iterator::zip_wrapper<Iter...> ends): m_begins(std::move(begins)), m_ends(std::move(ends))
|
||||||
{
|
{
|
||||||
static_assert((std::is_same_v<iterator_category, std::bidirectional_iterator_tag> ||
|
static_assert((std::is_same_v<iterator_category, std::bidirectional_iterator_tag> ||
|
||||||
std::is_same_v<iterator_category, std::random_access_iterator_tag>),
|
std::is_same_v<iterator_category, std::random_access_iterator_tag>),
|
||||||
|
@ -413,8 +302,8 @@ namespace blt
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::reverse_iterator<iterator::zip_wrapper<iterator_category, Iter...>> m_begins;
|
std::reverse_iterator<iterator::zip_wrapper<Iter...>> m_begins;
|
||||||
std::reverse_iterator<iterator::zip_wrapper<iterator_category, Iter...>> m_ends;
|
std::reverse_iterator<iterator::zip_wrapper<Iter...>> m_ends;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -126,17 +126,17 @@ void test_pairs()
|
||||||
void test_zip()
|
void test_zip()
|
||||||
{
|
{
|
||||||
blt::log_box_t box(std::cout, "Zip Tests", 25);
|
blt::log_box_t box(std::cout, "Zip Tests", 25);
|
||||||
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3))
|
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, list_1))
|
||||||
{
|
{
|
||||||
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
|
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
|
||||||
}
|
}
|
||||||
BLT_TRACE("================================");
|
BLT_TRACE("================================");
|
||||||
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).take(3))
|
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, list_1).take(3))
|
||||||
{
|
{
|
||||||
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
|
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
|
||||||
}
|
}
|
||||||
BLT_TRACE("================================");
|
BLT_TRACE("================================");
|
||||||
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).take(3).rev())
|
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, list_1).take(3).rev())
|
||||||
{
|
{
|
||||||
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
|
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue