Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #87192 > unrolled thread
| Started by | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| First post | 2022-11-01 15:32 +0100 |
| Last post | 2022-11-06 10:34 +0100 |
| Articles | 19 — 5 participants |
Back to article view | Back to comp.lang.c++
What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-01 15:32 +0100
Re: What is this header good for ? "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-11-01 20:23 +0100
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-02 03:59 +0100
Re: What is this header good for ? Tony Oliver <guinness.tony@gmail.com> - 2022-11-02 04:45 -0700
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-02 14:33 +0100
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-02 04:02 +0100
Re: What is this header good for ? Muttley@dastardlyhq.com - 2022-11-02 16:59 +0000
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-02 18:45 +0100
Re: What is this header good for ? Öö Tiib <ootiib@hot.ee> - 2022-11-03 08:22 -0700
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-03 16:43 +0100
Re: What is this header good for ? Öö Tiib <ootiib@hot.ee> - 2022-11-03 09:06 -0700
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-04 20:12 +0100
Re: What is this header good for ? Öö Tiib <ootiib@hot.ee> - 2022-11-05 06:24 -0700
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-05 15:51 +0100
Re: What is this header good for ? Öö Tiib <ootiib@hot.ee> - 2022-11-05 09:44 -0700
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-05 18:11 +0100
Re: What is this header good for ? Öö Tiib <ootiib@hot.ee> - 2022-11-05 16:03 -0700
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-06 06:19 +0100
Re: What is this header good for ? Bonita Montero <Bonita.Montero@gmail.com> - 2022-11-06 10:34 +0100
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-01 15:32 +0100 |
| Subject | What is this header good for ? |
| Message-ID | <tjrakt$q076$1@dont-email.me> |
#pragma once
#include <type_traits>
template<typename T>
#if defined(__cpp_concpets)
requires std::is_scalar_v<T>
#endif
union ndi_t
{
ndi_t() = default;
ndi_t( T init );
ndi_t &operator =( T assign );
operator T();
T *operator &();
private:
T m_value;
};
template<typename T>
#if defined(__cpp_concpets)
requires std::is_scalar_v<T>
#endif
inline ndi_t<T>::ndi_t( T init ) :
m_value( init )
{
}
template<typename T>
#if defined(__cpp_concpets)
requires std::is_scalar_v<T>
#endif
inline ndi_t<T> & ndi_t<T>::operator =( T assign )
{
m_value = assign;
return *this;
}
template<typename T>
#if defined(__cpp_concpets)
requires std::is_scalar_v<T>
#endif
inline ndi_t<T>::operator T()
{
return m_value;
}
template<typename T>
#if defined(__cpp_concpets)
requires std::is_scalar_v<T>
#endif
inline T *ndi_t<T>::operator &()
{
return &m_value;
}
[toc] | [next] | [standalone]
| From | "Alf P. Steinbach" <alf.p.steinbach@gmail.com> |
|---|---|
| Date | 2022-11-01 20:23 +0100 |
| Message-ID | <tjrrnu$r9rf$1@dont-email.me> |
| In reply to | #87192 |
On 1 Nov 2022 15:32, Bonita Montero wrote: > #if defined(__cpp_concpets) That loooks lik a speling eror. A good-for-nothing header then. Cheers!, - Alf
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-02 03:59 +0100 |
| Message-ID | <tjsmdf$vv77$3@dont-email.me> |
| In reply to | #87193 |
Am 01.11.2022 um 20:23 schrieb Alf P. Steinbach: > On 1 Nov 2022 15:32, Bonita Montero wrote: >> #if defined(__cpp_concpets) > That loooks lik a speling eror. That's a feature-test macro defined by C++20. > A good-for-nothing header then. Thanks for your effort to have a deep understanding of my code. !
[toc] | [prev] | [next] | [standalone]
| From | Tony Oliver <guinness.tony@gmail.com> |
|---|---|
| Date | 2022-11-02 04:45 -0700 |
| Message-ID | <200d5938-8af5-4b2a-b37d-6b3b8d36b03fn@googlegroups.com> |
| In reply to | #87194 |
On Wednesday, 2 November 2022 at 02:59:13 UTC, Bonita Montero wrote: > Am 01.11.2022 um 20:23 schrieb Alf P. Steinbach: > > > On 1 Nov 2022 15:32, Bonita Montero wrote: > > >> #if defined(__cpp_concpets) > > > That loooks lik a speling eror. > That's a feature-test macro defined by C++20. No, it isn't. You seem to be trying (and failing) to spell "__cpp_concepts". "__cpp_concpets" does not appear anywhere in N4860.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-02 14:33 +0100 |
| Message-ID | <tjtrir$16ctt$1@dont-email.me> |
| In reply to | #87196 |
Am 02.11.2022 um 12:45 schrieb Tony Oliver: > On Wednesday, 2 November 2022 at 02:59:13 UTC, Bonita Montero wrote: >> Am 01.11.2022 um 20:23 schrieb Alf P. Steinbach: >> >>> On 1 Nov 2022 15:32, Bonita Montero wrote: >> >>>> #if defined(__cpp_concpets) >> >>> That loooks lik a speling eror. >> That's a feature-test macro defined by C++20. > > No, it isn't. You seem to be trying (and failing) to spell "__cpp_concepts". > "__cpp_concpets" does not appear anywhere in N4860. Ok, I removed it anyway, requiring concepts always now because I'm using a concept which should stop specializations under a certain condition.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-02 04:02 +0100 |
| Message-ID | <tjsmkg$1004m$1@dont-email.me> |
| In reply to | #87192 |
That's the final version of my header, now it requires C++20:
#pragma once
#include <type_traits>
template<typename T>
requires std::is_trivially_destructible_v<T>
union ndi_t
{
ndi_t();
ndi_t( T const &init );
ndi_t &operator =( T const &assign );
operator T &();
T *operator &();
T *operator ->()
requires std::is_class_v<T>;
private:
union U
{
U();
U( T const &value );
T m_value;
} m_u;
};
template<typename T>
requires std::is_trivially_destructible_v<T>
inline ndi_t<T>::U::U()
{
}
template<typename T>
requires std::is_trivially_destructible_v<T>
inline ndi_t<T>::U::U( T const &value ) :
m_value( value )
{
}
template<typename T>
requires std::is_trivially_destructible_v<T>
inline ndi_t<T>::ndi_t() :
m_u()
{
}
template<typename T>
requires std::is_trivially_destructible_v<T>
inline ndi_t<T>::ndi_t( T const &init ) :
m_u( init )
{
}
template<typename T>
requires std::is_trivially_destructible_v<T>
inline ndi_t<T> & ndi_t<T>::operator =( T const &assign )
{
m_u.value = assign;
return *this;
}
template<typename T>
requires std::is_trivially_destructible_v<T>
inline ndi_t<T>::operator T &()
{
return m_u.m_value;
}
template<typename T>
requires std::is_trivially_destructible_v<T>
inline T *ndi_t<T>::operator &()
{
return &m_u.m_value;
}
template<typename T>
requires std::is_trivially_destructible_v<T>
inline T *ndi_t<T>::operator ->()
requires std::is_class_v<T>
{
return &m_u.m_value;
}
[toc] | [prev] | [next] | [standalone]
| From | Muttley@dastardlyhq.com |
|---|---|
| Date | 2022-11-02 16:59 +0000 |
| Message-ID | <tju7mb$1l95$1@gioia.aioe.org> |
| In reply to | #87195 |
On Wed, 2 Nov 2022 04:02:53 +0100 Bonita Montero <Bonita.Montero@gmail.com> wrote: >That's the final version of my header, now it requires C++20: And this explosion in an ASCII factory does what exactly?
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-02 18:45 +0100 |
| Message-ID | <tjuabe$17gkq$1@dont-email.me> |
| In reply to | #87198 |
Am 02.11.2022 um 17:59 schrieb Muttley@dastardlyhq.com: > Bonita Montero <Bonita.Montero@gmail.com> wrote: >> That's the final version of my header, now it requires C++20: > And this explosion in an ASCII factory does what exactly? It's a class that wraps simple types that don't have destructors and omits their default-construction. With that you can f.e. have a vector of ints (vector<ndi_t<int>>) and the ints aren't default-constructed, i.e. their value is arbitrary. That might save a lot of CPU-time if you grow a large vector in one step so that you can omit the initialization if you do it yourself anyway. But there are other standard types like pair<> where the members are also default-initialized. So if you have a vector of such pairs where .first and .second are ndi_t-types this also might save some CPU-time. There are a number of overloaded operators so that you can handle such an ndi_t<>-object nearly the same way you would handle the corresponding type it encapsulates. F.e. you can take the ndi_t<> object's address with & and you get the address of the encapsulated type. Or you can access the members of the encapsulated object if it is a class type with the ->-operator, similar to a smart pointer.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2022-11-03 08:22 -0700 |
| Message-ID | <33a066b2-bdab-4423-97dd-36c2d96e431bn@googlegroups.com> |
| In reply to | #87199 |
On Wednesday, 2 November 2022 at 19:45:33 UTC+2, Bonita Montero wrote: > Am 02.11.2022 um 17:59 schrieb Mut...@dastardlyhq.com: > > > Bonita Montero <Bonita....@gmail.com> wrote: > > >> That's the final version of my header, now it requires C++20: > > > And this explosion in an ASCII factory does what exactly? > It's a class that wraps simple types that don't have destructors and > omits their default-construction. With that you can f.e. have a vector > of ints (vector<ndi_t<int>>) and the ints aren't default-constructed, > i.e. their value is arbitrary. > > That might save a lot of CPU-time if you grow a large vector in one > step so that you can omit the initialization if you do it yourself > anyway. How it "might"? IMHO not with what vector is required to do. We grow by your example a vector like vec.resize(large_size). That calls void std::vector<T,A>::resize(size_type count, T value = T()); That function is required to copy construct each element that we did grow using that "value" as argument. On our case that T is supposed to be ndi_t<Something>. Therefore resize() will use compiler-generated constructors ndi_t<Something>::ndi_t( ndit_t const &init ) and those are required to diligently copy that uninitalized Something value from inside of that T() object. So what you expect a compiler can "save" here compared to std::vector<Something> ? > But there are other standard types like pair<> where the > members are also default-initialized. So if you have a vector of > such pairs where .first and .second are ndi_t-types this also might > save some CPU-time. > There are a number of overloaded operators so that you can handle > such an ndi_t<>-object nearly the same way you would handle the > corresponding type it encapsulates. F.e. you can take the ndi_t<> > object's address with & and you get the address of the encapsulated > type. Or you can access the members of the encapsulated object if > it is a class type with the ->-operator, similar to a smart pointer.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-03 16:43 +0100 |
| Message-ID | <tk0nj8$1g58o$1@dont-email.me> |
| In reply to | #87206 |
Am 03.11.2022 um 16:22 schrieb Öö Tiib: > How it "might"? IMHO not with what vector is required to do. > We grow by your example a vector like vec.resize(large_size). > That calls void std::vector<T,A>::resize(size_type count, T value = T()); > That function is required to copy construct each element that we > did grow using that "value" as argument. The default-constructor of my ndi_t<> is empty so that the loop initia- lizing the new elements is optimized away. My ndi_t<> is a union so the member m_value isn't initialized by default but needs explicit initali- zation with the constructor of my union and I omit that.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2022-11-03 09:06 -0700 |
| Message-ID | <fc035527-6558-4ca4-ade9-e379a8bc065dn@googlegroups.com> |
| In reply to | #87207 |
On Thursday, 3 November 2022 at 17:43:54 UTC+2, Bonita Montero wrote: > Am 03.11.2022 um 16:22 schrieb Öö Tiib: > > > How it "might"? IMHO not with what vector is required to do. > > We grow by your example a vector like vec.resize(large_size). > > That calls void std::vector<T,A>::resize(size_type count, T value = T()); > > That function is required to copy construct each element that we > > did grow using that "value" as argument. > > The default-constructor of my ndi_t<> is empty so that the loop initia- > lizing the new elements is optimized away. My ndi_t<> is a union so the > member m_value isn't initialized by default but needs explicit initali- > zation with the constructor of my union and I omit that. What? The resize() is required to copy construct new elements from "value" parameter, not default construct new elements. What default constructor of ndi_t does does not matter in context where it is not called.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-04 20:12 +0100 |
| Message-ID | <tk3o67$1v8om$1@dont-email.me> |
| In reply to | #87209 |
Am 03.11.2022 um 17:06 schrieb Öö Tiib: > What? The resize() is required to copy construct new elements from > "value" parameter, not default construct new elements. ... The appended elements are initialized by default if you don't pass a default-value given to the parametrized constructor. So you can gigabytes of appended elements that aren't default-initialized and when you have an operating system that overcommits the appended memory pages aren't even assigned to physical pages until you write-touch them.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2022-11-05 06:24 -0700 |
| Message-ID | <c061094f-7064-4913-a547-1a2ffa4d84e5n@googlegroups.com> |
| In reply to | #87235 |
On Friday, 4 November 2022 at 21:12:23 UTC+2, Bonita Montero wrote: > Am 03.11.2022 um 17:06 schrieb Öö Tiib: > > > What? The resize() is required to copy construct new elements from > > "value" parameter, not default construct new elements. ... > > The appended elements are initialized by default if you don't pass > a default-value given to the parametrized constructor. So you can > gigabytes of appended elements that aren't default-initialized and > when you have an operating system that overcommits the appended > memory pages aren't even assigned to physical pages until you > write-touch them. Plain wrong third time. That is not what resize is required to do. If you omit the value parameter then it is required to default construct it and then copy construct the result. Can be billions of times if you resized to billions of elements.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-05 15:51 +0100 |
| Message-ID | <tk5t95$2gncr$1@dont-email.me> |
| In reply to | #87250 |
Am 05.11.2022 um 14:24 schrieb Öö Tiib: > Plain wrong third time. That is not what resize is required to do. That depends on what you want. If you want the appended elements not to be default-initialized because you overwrite the element yourself later or you don't initialize it at all because you want partitially complete pages which arent assigned to phyisical memory (unter Linux these pages arent even reseved from swap with overcommitting) my ndi_t union is the right thing. The class only works if the encapsulated type has a trivial destructor which is restricted by a concept to prevent to do the wrong things with my union.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2022-11-05 09:44 -0700 |
| Message-ID | <9268ea98-1e79-492a-8f78-6ab52005a441n@googlegroups.com> |
| In reply to | #87251 |
On Saturday, 5 November 2022 at 16:51:35 UTC+2, Bonita Montero wrote: > Am 05.11.2022 um 14:24 schrieb Öö Tiib: > > > Plain wrong third time. That is not what resize is required to do. > > That depends on what you want. Nope. If a function is not required by standard to call your mutilated default constructor then it does not start to call it (and optimize away) because you want. Your wishes are irrelevant.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-05 18:11 +0100 |
| Message-ID | <tk65g1$2ik4v$1@dont-email.me> |
| In reply to | #87252 |
Am 05.11.2022 um 17:44 schrieb Öö Tiib: >> That depends on what you want. > Nope. If a function is not required by standard to call your mutilated > default constructor then it does not start to call it (and optimize away) > because you want. Your wishes are irrelevant. Of course the default-construction loop on the appended elements is optimized away, that's what my ndi_t<>-union is for; this saves CPU time. You simply don't understand the purpose.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2022-11-05 16:03 -0700 |
| Message-ID | <26dcb12b-18e1-4eca-8a12-85dd4ac414d7n@googlegroups.com> |
| In reply to | #87253 |
On Saturday, 5 November 2022 at 19:11:47 UTC+2, Bonita Montero wrote: > Am 05.11.2022 um 17:44 schrieb Öö Tiib: > > >> That depends on what you want. > > > Nope. If a function is not required by standard to call your mutilated > > default constructor then it does not start to call it (and optimize away) > > because you want. Your wishes are irrelevant. > > Of course the default-construction loop on the appended elements > is optimized away, that's what my ndi_t<>-union is for; this saves > CPU time. The resize has never been required to have default construction loop in it; resize is required to have loop of copy initialization. > You simply don't understand the purpose. I perfectly understand that you wish that there is default construction loop in vector resize, just that it is not so in our reality.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-06 06:19 +0100 |
| Message-ID | <tk7g59$2uu4h$1@dont-email.me> |
| In reply to | #87263 |
Am 06.11.2022 um 00:03 schrieb Öö Tiib: > The resize has never been required to have default construction loop > in it; resize is required to have loop of copy initialization. https://en.cppreference.com/w/cpp/container/vector/resize "additional default-inserted elements are appended". > I perfectly understand that you wish that there is default construction > loop in vector resize, just that it is not so in our reality. You're a idiot.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-11-06 10:34 +0100 |
| Message-ID | <tk7v2o$evi$1@gioia.aioe.org> |
| In reply to | #87263 |
I've written a little program to demonstrate the advantage of my ndi_t
union:
#include <iostream>
#include <vector>
#include <chrono>
#include <cmath>
#include <sstream>
#include "ndi_t.h"
using namespace std;
using namespace chrono;
int main()
{
auto bench = []<typename T, typename Touch>( T t, Touch touch ) -> double
requires requires( Touch touch, vector<T> &vt ) { { touch( vt ) }; }
{
constexpr size_t N = (size_t)1 << 30;
vector<T> vt;
auto start = high_resolution_clock::now();
vt.resize( N );
touch( vt );
return (double)duration_cast<nanoseconds>(high_resolution_clock::now()
- start).count() / 1.0e6;
};
auto ndiTouch = []( vector<ndi_t<char>> &ndiVec )
{
for( size_t i = 0; i < ndiVec.size(); ndiVec[i] = 0, i += 0x1000 );
};
double
tChar = bench( char(), []( vector<char> const & ) {} ),
tNdi = bench( ndi_t<char>(), []( vector<ndi_t<char>> const & ) {} ),
tNdiTouch = bench( ndi_t<char>(), ndiTouch );
cout << "char: " << tChar << "ms" << endl;
cout << "ndi_t<char>: " << tNdi << "ms" << endl;
cout << "ndi_t<char> (touch): " << tNdiTouch << "ms" << endl;
}
It benchmarks the time to resize a char-vector to one GB. My ndi_t
union is about 30.000 times faster on my Linux computer. This is
while such large allocations aren't pooled by your memory allocator
but directly fetched from the kernel in multiples of pages. If this
pages aren't touched they remain unassigned to actual physical memory.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web