Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Slurps Mad Rips
Jan 25, 2009

Bwaltow!

hackbunny posted:

what's the realloc problem?

I stopped caring about allocators when I found they couldn't be written as adapters for lots of common allocators, and EA's paper on their gamedev stl validated me. it seems some (all?) of those issues were finally addressed and I pleasantly note that deallocate's size argument can now be, basically, ignored (still no idea why it even has a size argument)


The realloc problem is that (in the standard) we can't have allocators with a reallocate function because realloc copies the data at the old location and that will most likely break types that aren't TriviallyCopyable. If realloc didn't do a copy it'd probably be part of the standard allocator interface because it would allocate a new block or simply grow the old one and the user could check to see if they needed to do the copy themselves. Its doable on several platforms but at that point you're writing a whole new stdlib. maybe well get lucky with std2: template boogaloo

hackbunny posted:

huh, you're right, I was overthinking it. I'm still very unfamiliar with type_traits, vararg templates etc. because back in my day we had to trait our types uphill both ways etc.

except for one thing:

C++ code:
v->template cast<I>()
what fresh new hell is this?

that is what happens when you have a template function in a templated class where it requires you to explicitly specify the template function's parameter and you're calling it from a templated function where you dont know the inner templates of the template class.

it is only occasionally necessary, but is the reason get<I> is not a member function for std::tuple because then you'd see "my_tuple.template get<I>()" everywhere. if you only use GCC you might not have run into it because they did a thing where it didn't care if the template keyword was there or not

(it was also a poor choice on my part because i was trying to not let someone gain direct access to the underlying storage of the variant)
edit: (and i was also getting differing behavior regarding friends and template functions under gcc and clang that is probably not an issue anymore)

Adbot
ADBOT LOVES YOU

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

Slurps Mad Rips posted:

The realloc problem is that (in the standard) we can't have allocators with a reallocate function because realloc copies the data at the old location and that will most likely break types that aren't TriviallyCopyable. If realloc didn't do a copy it'd probably be part of the standard allocator interface because it would allocate a new block or simply grow the old one and the user could check to see if they needed to do the copy themselves. Its doable on several platforms but at that point you're writing a whole new stdlib. maybe well get lucky with std2: template boogaloo

oh right, I hadn't thought about it. so when say a vector runs out of capacity, it has to allocate a whole new vector and copy itself to it? :psyduck: (or move if T supports it I guess)

Slurps Mad Rips
Jan 25, 2009

Bwaltow!

hackbunny posted:

oh right, I hadn't thought about it. so when say a vector runs out of capacity, it has to allocate a whole new vector and copy itself to it? :psyduck: (or move if T supports it I guess)

it used to be that simple
it only moves if the move constructor is noexcept. hence, the std::move_if_noexcept function, which is allowed to waive the strong exception guarantee if the move constructor is not noexcept and there is no copy constructor.

Bloody
Mar 3, 2013

I am not convinced c++ is a programming language. every conversation about it seems as orthogonal to every other programming chat as a conversation about Verilog would seem

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy
com has had VARIANT for like 20 years, idk what the big deal is

VikingofRock
Aug 24, 2008




Bloody posted:

I am not convinced c++ is a programming language. every conversation about it seems as orthogonal to every other programming chat as a conversation about Verilog would seem

C++ is a programming language for lawyers, right down to the laws not being accessible to anyone without $100 lying around to spend on the standard.

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

chmods please posted:

com has had VARIANT for like 20 years, idk what the big deal is

it's not typesafe. say it contains an integer and you access it as a string. c++ variant will stop you at compile time

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
the type safety was inside you all along

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av
you know what else is inside of me?

Xarn
Jun 26, 2015

Bloody posted:

I am not convinced c++ is a programming language. every conversation about it seems as orthogonal to every other programming chat as a conversation about Verilog would seem
But Verilog is a programming language?



MrMoo posted:

For a spiffy SPSC queue read you a Lynx Queue, using page faults around a ring buffer to avoid socket contention on the head/tail pointers.

Ok, that is really cool idea.

Athas
Aug 6, 2007

fuck that joker
Jesus Christ, while I think type-level programming in Coq or Idris is complicated, at least there is some coherency and fundamental simplicity at play. C++ is just a nightmare. Even Haskell isn't close to that complexity.

Cybernetic Vermin
Apr 18, 2005

Xarn posted:

But Verilog is a programming language?


Ok, that is really cool idea.

page table fuckery is so dangerous/unpredictable though, would not go that route even with the numbers looking good in their tests

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Athas posted:

Jesus Christ, while I think type-level programming in Coq or Idris is complicated, at least there is some coherency and fundamental simplicity at play. C++ is just a nightmare. Even Haskell isn't close to that complexity.

haskell will only ever hope to aspire to make functional programming as complicated as c++.

every time i deal with the inefficacy of c# templates i die on the inside and dream of again being abused by c++ tho.

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av
c c++14 s: implementing a template polymorphic visit method :aaaaa:

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

VikingofRock posted:

C++ is a programming language for lawyers, right down to the laws not being accessible to anyone without $100 lying around to spend on the standard.

the source for the standard is on github these days, so there's no reason to actually buy the official publication

Bloody
Mar 3, 2013

Xarn posted:

But Verilog is a programming language?

debatable

sarehu
Apr 20, 2007

(call/cc call/cc)

hackbunny posted:

c c++14 s: implementing a template polymorphic visit method :aaaaa:

Huh. There exists a variant impl under the "eggs" namespace somewhere on Github. https://github.com/eggs-cpp/variant

I replaced boost::variant uses with it in RethinkDB and stuff still worked, and it compiled 10% faster.

JawnV6
Jul 4, 2004

So hot ...

Bloody posted:

debatable
no, it's not

Arcsech
Aug 5, 2008

JawnV6 posted:

no, it's not

its a programming language in the same sense that xml/xslt is. like, you can use it as a programming language, but you shouldn't

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

sarehu posted:

Huh. There exists a variant impl under the "eggs" namespace somewhere on Github. https://github.com/eggs-cpp/variant

I replaced boost::variant uses with it in RethinkDB and stuff still worked, and it compiled 10% faster.

JawnV6
Jul 4, 2004

So hot ...

Arcsech posted:

its a programming language in the same sense that xml/xslt is. like, you can use it as a programming language, but you shouldn't
my dictionary has "hardware description" and "programming" on different pages

if we're talking about "you can use a hdl simulator as a runtime" the language is so stretched as to be meaningless. makes the scaffolding between a interpreted language vs. compiled look trivial.

Bloody
Mar 3, 2013

:goonsay: verilog is turing complete

Bloody
Mar 3, 2013

in fact in the strictest sense of turing completeness, its probably rather good at it

JawnV6
Jul 4, 2004

So hot ...
but whats a pl without a runtime

Bloody
Mar 3, 2013

the build process takes around 3 months

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
"how can it be a PL if it can't even print strings?" :hurr:

qntm
Jun 17, 2009

Gazpacho posted:

"how can it be a PL if it can't even print strings?" :hurr:

I was going to make a programming language with no I/O capability whatsoever, and adding such would be specifically forbidden in the licence

it would be fully-featured, but the compiler would optimise every program down to a no-op

JawnV6
Jul 4, 2004

So hot ...

Gazpacho posted:

"how can it be a PL if it can't even print strings?" :hurr:

verilog doesn't "communicate instructions to a machine", the string-printing faculties are always giant rafts of complexity that would put most vm's & interpreted environments to shame

it's not a programming language and any hint of that reductive thinking actively hinders doing anything useful in it

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
the real hindrance is believing that there's a bright-line distinction between hw and sw

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

JawnV6 posted:

but whats a pl without a runtime

a miserable little pile of secrets

JawnV6
Jul 4, 2004

So hot ...
please don't troll this thread gaz, tia

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Malcolm XML posted:

a miserable little pile of srams

Arcsech
Aug 5, 2008

JawnV6 posted:

my dictionary has "hardware description" and "programming" on different pages

if we're talking about "you can use a hdl simulator as a runtime" the language is so stretched as to be meaningless. makes the scaffolding between a interpreted language vs. compiled look trivial.

why do you think i compared it to using loving xml, a document markup language, as a programming language

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
HDLs are used to describe information processes. idk where you get this idea that they must describe it to another information processor to be a PL

and if you don't work in business IT you might be forgiven for not realizing how relevant chip architecture concepts are in modern distributed architectures, e.g. enterprise buses and service opcodes etc

JawnV6
Jul 4, 2004

So hot ...

Arcsech posted:

why do you think i compared it to using loving xml, a document markup language, as a programming language
the process of constructing a program in xml and verilog are vastly different though, you're not smuggling transformations around with decoration, it's entirely new constructs from System Verilog bolted onto the core language that only interact with a particular simulation environment

also, i have no idea what xml/xslt are and im not one to let ignorance hold me back from stating an opinion

JawnV6
Jul 4, 2004

So hot ...

Gazpacho posted:

HDLs are used to describe information processes. idk where you get this idea that they must describe it to another information processor to be a PL
oh, gosh, here I was using a definition instead of vaguely shooting from the hip, specifically "A programming language is a formal computer language designed to communicate instructions to a machine, particularly a computer". HDL's and programming languages are both computer languages, this does not imply that they're the same thing

Gazpacho posted:

and if you don't work in business IT you might be forgiven for not realizing how relevant chip architecture concepts are in modern distributed architectures, e.g. enterprise buses and service opcodes etc
and if you can't expand "igbt" and understand why no amount of calling it "analog software working with electrical and thermal channels" is in any way sensible, you might be forgiven for thinking this:

Gazpacho posted:

the real hindrance is believing that there's a bright-line distinction between hw and sw

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

JawnV6 posted:

im not one to let ignorance hold me back from stating an opinion
noted

Bloody
Mar 3, 2013

with the power of Icarus Verilog, your Verilog can indeed be computer instructions!!!

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av
ok, let's step back and rationalize. implementing variant, even a lovely buggy limited version of it, takes a huge amount of code, almost all of it metaprogramming. what does variant do?
  • it contains another object, of any of the types specified in its parameter list. templates can generate a lot of compile time type information, code and data, but a thing they can't create is new names for things. variant can't, therefore, contain a union, because we'd have to create a union field for each of the types, and fields have to be named, and metaprogramming can't name things. so, ironically, the standard discriminated union container is not, in fact, a discriminated union (unlike say, array which is a wrapper for a C array, vector which is a wrapper for a dynamically sized C array, string, etc.). what we need, instead, is a blob (like say, a char array) of the appropriate size and alignment to contain any of the possible types. type_traits includes just such a blob type, aligned_union. pity because of all the things variant requires, this was the only one I already knew how to write
  • as a discriminated union, it contains a discriminant. this will simply be a field of type size_t that identifies which of the possible types is currently active
  • default-constructibility is not a requirement (I won't implement it), but destructibility is. variant's destructor, like many other of its methods, needs to be polymorphic: depending on what type it currently contains, it must call the appropriate destructor. this is a bitch and a half to implement, but at least we'll only have to do it once and reuse it everywhere. we need a generic, internal static (non-instance) method, that we'll call destruct, which calls the destructor of an arbitrary object passed as its argument (yes, this is legal. and yes, it's unsafe). we then need a method, that we'll call visit, that takes a reference to a function-like object as its sole argument, that we'll call visitor. the visitor must have an overloaded call operator that can take all the possible types the variant could contain. you'd think you could just pass the generic destruct method, but you can't: unspecialized template functions are not things that exist, they are far too abstract to be passed around as values. not that an overloaded function is much better: an overloaded function, without some information to pick a specific overload, is a very abstract entity that can't be passed as an argument to visit, either. what's both generic and concrete enough, tough, is a generic lambda:
    C++ code:
    // I decided to call mine either, instead of variant
    ~either()
    {
    	visit([](auto&& value){
    		// no need to use forward, for once
    		destruct(value);
    	});
    }
    
    destruct is trivial and I won't discuss it. visit is, hoo boy. visit is first and foremost a runtime dispatcher: it switches on the union discriminator, and calls the appropriate overload of the visitor. another thing templates can't do (at least not trivially) is generating switch statements. you can't make arrays of lambdas, either, for stupid reasons, so we'll have to make an array of function pointers... that actually point to stateless lambdas. barf. elements of arrays all have the same type, so our stateless lambdas will have a prototype like void(Visitor&& v, void *raw_value); internally, they'll each contain a cast of raw_value to the appropriate type, and a call to the visitor. each of these little dispatchers will be generated by a generic factory method like this:
    C++ code:
    // VoidT instead of plain void so that const void can be used for const methods
    template<class Visitor, class T, class VoidT>
    static auto make_dispatcher() -> void(*)(Visitor&&, VoidT *)
    {
    	return [](Visitor&& v, VoidT *raw_object) -> void
    	{
    		std::forward<Visitor>(v)(*static_cast<T *>(raw_object));
    	};
    }
    
    we put all these little dispatchers in an array, select the dispatcher indexed by the current value of the discriminator, and we call it passing it the visitor, through forwarding, and a raw pointer to our internal aligned_union. the cast in the dispatcher "doesn't do anything" (not 100% correct), it just changes the type of the argument to select the right overload/specialization of the visitor. and yes, given N possible types of the variant and M possible visitor types, this will generate M tables of N pointers. they may be inlined, they may be not, who knows. but the visit method, once you dehumanize yourself and face to runtime polymorphism, isn't that hard, conceptually
  • ... what's a little harder is giving visit a meaningful return type instead of void! luckily, C++ has the basic block for this as the common_type metafunction. we have to simulate calling all possible overloads of the visitor: metafunction result_of resolves a single overload, we just have to apply it to the list of the variant's possible types to map them to a list of visitor return types. then we reduce the list of return types with common_type:
    C++ code:
    template<class Visitor>
    auto visit(Visitor&& v) -> std::common_type_t<std::result_of_t<Visitor(Types)>...>
    { // ...
    
    as usual with c++ metaprogramming, easy, readable code like this is almost guaranteed to be subtly wrong. we'll see
    what does "common type" mean anyway? it's defined as the type of a ternary conditional operator expression. in C, the two branches of the ternary operator can have completely different types, which is scary and enables horrible hacks. c++ is much more restrictive and will only let you use different types if they're related somehow, eg. if the true branch evaluates to a long and the false to an int, the expression evaluates to a long. basically it's as if visit was a big chain of ternary conditionals: discriminator == 0 ? visit(type_0) : discriminator == 1 ? visit(type_1) etc.
  • a variant can be copied from another variant of the same kind if and only if all types it can contain are copyable. the standard library provides metafunction is_copy_constructible to check whether a type is copy constructible. in c++17 we'll check whether a variant can be copied like this: (... && is_copy_constructible<Types>::value...) - this calls is_copy_constructible on each type in Types, maps the list of types to a list of booleans, and then reduces to a single boolean by folding the list two-by-two with the logical and operator. c++14 can map, but it can't reduce, so we'll need a function like this:
    C++ code:
    template<class HeadT>
    constexpr auto&& fold_and(HeadT&& head)
    {
    	return std::forward<HeadT>(head);
    }
    
    template<class HeadT, class... TailT>
    constexpr auto fold_and(HeadT&& head, TailT&&... tail)
    {
    	return std::forward<HeadT>(head) && fold_and(std::forward<TailT>(tail)...);
    }
    
    (it can't be simply called and because it's a reserved word, an alternate spelling of &&). thus the existence of the copy constructor will be guarded with enable_if_t<fold_and(is_copy_constructible<Types>::value...), /*etc.*/>. enable_if_t is a disgusting loving hack and it's a disgrace that the language has to resort to hacks of its overload resolution algorithm to perform pattern matching, instead of using a switch-like syntax
    the body of the constructor will be based, like the destructor, on the visit method. we'll use placement new to build a copy of the current value of the variant to be copied in-place, in our internal aligned_variant
    C++ code:
    // the enable_if_t horror has been omitted for simplicity (and piety)
    either(const either& other): m_index(other.m_index)
    {
    	other.visit([this](auto&& other_value) {
    		using value_type = std::remove_reference_t<decltype(other)>;
    		new(&m_storage) value_type(other_value);
    	});
    }
    
    reminder that placement new is horribly unsafe (and really hard to find in a code audit!)
  • same for the move constructor, except using is_move_constructible and invoking the move constructor(s)

and for now I'll stop here or I'll never go to sleep

if this sounds well-reasoned, well, don't worry: this is the reasoned post-mortem of a full day of throwing poo poo at the wall to see what stuck. my usual holistic approach isn't helping much: there is so, so much to learn, and the endless quirks, traps and pitfalls of template metaprogramming make it really hard to apply my (vague) functional programming knowledge, because so many times the obvious solution is in fact a syntax error

hackbunny fucked around with this message at 01:50 on Dec 1, 2016

Adbot
ADBOT LOVES YOU

raminasi
Jan 25, 2005

a last drink with no ice
did anyone else start saying "oh what no no no no" to themselves while reading that

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply