 Hello Hopefully everyone can hear me It's our next speaker and I should be starting in a couple minutes. It's gonna be Stefan Bergman You'll be talking about C++ Stefan if you're here, can you share your screen? Do you happen to have earplugs? I'm doing it Can hear you yeah, right? Do you have earplugs on? No, no, no, would you mind if you have some I don't have any brown Okay Sounds good start when you're ready. Thank you for presenting. Yeah, so yeah, okay, I guess we can start So I'll come to another installment of the C++ Big Show Got a little bit of a timer this year So let's see What do we have? The usual schedule update of what C++ features we're using in LibreOffice and Meanwhile, we reached the point where We have full support or nearly full support of C++ 17 in our code base in the master branch at least Being a bit aggressive with the Microsoft compiler for example, so we require the latest 2019 there by now, so that we have a smooth experience Which allows us to unconditionally use all these features like structured bindings now Where you can like Reconstruct if you have a pair and want to bind both of its members to variables Like romance Pattern matching for C++ that's available now We have guaranteed copy allusion, so we use that in a couple places where we have some class that is non-copyable But we still want to have some actually Function that returns an instance of that in the past year had to use pointers for that and give a location and You can just return it now because There won't be any copies involved in moving it into its destination So that's great reducing some some mess in the code With class template argument deduction. I'll talk about that later in some Example code, but I'm delving into constant expression if Compile time you can decide whether some branch is taken or not We use it in a couple places not that many now It's mostly useful for for building Plumbing functionality deep down in the code. What's also great is all these Attributes there now available like Fall through and so that you can annotate your Switch branches switch cases that they fall through to the next one and we're in the past you used to use some Random commands there these may be unused and notice card things that are useful to Annotate code that like The results must not be or must be used or may not be used. We have some some macros for that always And then we now could get rid of these and just use the standard ways now Which is good Also some useful functionality from the standard library tribute things like this clamp function that you have Want to have a value that is below within a min max range There's a function for that. You can use that. There's a standard optional We use we have the standard stream view come back to that as well It's all of these are now Available across all platforms and we can just have to use them so having that Always one more Because that is always delivering more The plus was 20 is More that's officially done by now and Every three years they want to bring out a new standard so see bus bus 23 will eventually come at some point and bring even more features We In the past what we did in our configure script was look what the latest flex the compiler supported were and Enabled them. So if you had a compiler that enabled Standard speed bus bus 20 or 2 a as it was called For finalization, then we would automatically pick that up Bust a bit of a problem in some cases Because some compilers would allow it and which is not up to the task of them compiling the code As what they thought Or what they had implemented of the latest standard by them So what I then did at one point is change that into an opt-in situation where if you want to now have something a compiler that goes beyond C++ 17 you need to opt-in with a configure switch of the latest C++ which then for the GCC playing Enables C++ 20 is available and for the Microsoft compiler is that C++ latest Which on which I stole the name For example, there was a as well in mentioned yesterday The covariate you think doesn't support anything beyond C++ 17 yet There was some thing with some Yeah, what I mentioned here the bumpy ride things so Some more stuff gets deprecated in C++ 20 so that you would get deprecation warnings about that that you have and wanting to enable and some things even got to remove completely Like some redundant members from the standard elevator stuff and that was used down below some boost Things and boosts Finally map or whatever and we used that in one place so I went in and Updated our version external boost version that we have fun though But of course that doesn't work for For other user for for the distribution for example Linux distros within their own boost So yeah, that that switch now helps to hide all the new features that your compiler money yet for it. There's also this Upcoming issue with The operators equal operator on equal operator These now generate or if you have to call of them in your code and the compiler in C++ 20 now also Besides all the all the overload that it finds all these and checks and order it also generates synthetic versions of these like the operators the parameters Reversed so if you have a case where you have your own operator bool defined for a class and The major slight mistake there like it takes its argument by cons But the operator itself is a non cons member function and these two arguments don't match a few votes then so you have to Viable overloads there on principle side by the compiler That clash with each other so it doesn't know which is the best one to choose so it Gives up and chooses none This was a common issue with lots of our external code Send lots of Patches upstream to be various Projects they happily accepted them so people if you have any questions or commands guess it works if you just Open your make and then Go ahead and ask Yeah, the new features How useful are them are they to use actually in the code not that much Yet because of course we have to keep the code in the way that it compiles for both 17 and later So there's not that much that we're using yet Like they have the standard span Which is just a view of something of a range So a pointer and account similar to string you a generalized string doing away We have that as as a as a wrapper in that all three tools thing and all these other things these Planned and optional and string you they also started out as as wrappers and The real things over time when they become saleable everywhere With a few places where we whether use features With a with an if death So we check for for cons evil and we have one place where we check for constant in it So cons evil is Similar to const extra comes expression thing you can Annotate a function as cons evil and then it is forced to evaluate at compile time The const expert it just tries to compile it or tries to evaluate a compile time And when that doesn't work it falls back to run time Cons value tell the compiler you have to evaluate this that That's a compile time. I will see one use of that later Cons in it is similar. It's for variables. So you tell the variable You tell the compiler you need to initialize this At compile time with this value It's like it's a Cons expert variable also needs to be initialized at compile time of then the variable itself is cons so this is like a non cons cons expert variable and Yeah, we have one place in the code. I think where we try to Populate a vector and then sort it and then initialize Decided to a variable or initialize a variable with it and I marked this with this if death so If eventually Compilers come around to that do support this then you pick that up there, but I think none of the compilers and standard libraries yet supported At least I've never seen it Or detected as true I configure or I made a mistake in the Figure check So what we don't use make any use yet of New stuff in C++ 20 like the concept or module for the big new features or even the spaceship operator. I think you could Get into using that so that would simplify some cases where you have all the Compatient operators or a class and With the spaceship thing you just need to define that one and it and tells you Other two barrier whether two values are less or equal or or greater And then you write for the other other operators from that which is pretty useful So we could if death maybe start if death that and simplify code over along the run So that's where we stand now So I think I thought I'll do a little case study of How we actually use some of these new features or try to make use of them and when I thought about a Good example Some code that could show showcase highlight some of that There's always these wonderful string things and Some the benefit is or the good thing is we use them in so many places But if you change anything there you'll probably find all the corner cases And also maybe bring some benefit to to run time even to the overall Time it takes a lever office for example start up or how much memory it consumes and so on I'm so a little recap What did strings look like they can open office times we have these wonderful long Mumbos that you needed to type every time you wanted to Use an innocent little string And we wash thankfully came around and Sugared that a bit and then de-fatted it a lot So that you could actually write something that you could read and comprehend I'm about getting distracted by all the boilerplate So again but We are still still using the same old under underlying layout Which is that a string Is nothing but a pointer to a ref counted block in memory Has this ref count You see my cursor hope so But it makes a bit of a sense what I'm talking about So you have this this ref count you have the length and you have the actual data in there So if you haven't new nice Shortly written Thing like constructing a string from from an actual literal The downside is that this is still an expensive thing at runtime. So what happens at runtime is that We set up this variable The user needed to allocate memory for this Block the memory variable size block where we then Set up ref count for one and length is three But we have three letters in here and then we need to copy over all these their characters in the original string in the literal and we expand them into zero expand them into 16 bit UT of 16 units But we anyway we need to copy this over. There's no chance around that So that means that whenever there's a use of a string At runtime then that means Rather expensive memory allocation going on so how could we Improve on that What we actually want is that all of this Is done at compile time all of these data structures are set up a compile time And we have this all in the read-only data section The string p data pointing to the block But the rest count that no longer because we would now be in the read-only data section We couldn't no longer Manipulate the rest count But it also wouldn't be needed any longer because this one is Is always there anyway, it's in the data section So it will never go away Even if there's no users of it around anymore So we thankfully already had a flag for the rest count Value for that But we use for the empty string mostly anyway yet So that indicates To the acquire and release functions Don't touch this one as it is a static one so we just we could just set that one and Then titulate the other values the other fields of the string and be happy and get rid of lots of Memory allocations So C++ 20 now that allow constexpo code For new and delete Which is great But it's only halfway done in a case in a way Because everything you Allocate with you they have to delete again before the constexpo function is done. So what we could do is Create this and with the right size that we have a place for all the members all the string members But then what we would need to delete it before we have Returned from from the function that sets up this data. So That won't fly yet, maybe into it the C++ 23 But what what we could do for now is just make this blob Okay, you string blob Static and in the read-only data and Then at runtime Create the OU string instance, which is just a pointer to that block Which is cheap to create because you just have one then variable that is a pointer So you just need to fill in the pointer at runtime. You don't have to Create any memory and copy around anything anymore You just set this pointer So that's a compromise That looks like it's a reasonable first step And I showed that that kind of work I didn't We can't replace of course all the OU strings because there's many of them that are created at runtime from variable data For not every OU string is Represents a string constant Where we could would want to use this optimization anyway But we already had a Helper class OU string literal That is used in many places to hold these Constants that was a nice target for me to actually try out these these things What it used to be the string literal is just the practically just a replacement for a standard string view so it Stored the pointer to the characters and their length And then there were lots of places in the code like when you use some some Name some string in multiple places. You give it a name as a variable those so first step what I needed was to Pimp this OU string that wrap up a bit by no longer containing Eight bit characters ASCII characters only But to make it take the same 16 bit code units that the OU string then uses so I just went in with some set Script and effectively and replaced all these places throughout the code to turn the 8 bit strings into 16 bit strings these 16 string users you They've been formed everywhere, which of course in me in the resulting binaries makes the strings a bit larger because they now contain 16 bit chunks mostly zeros in the upper bits But if you look at the results Then that was a very tiny amount of additional bytes that went into a full installation layout so Bob that wasn't that big of a problem and nobody complained that this move increased the Installation set size in that way, so Which brings us to the modified string literal class Which now has a constexpr Constructor that takes an array of These 16 bit UTF 16 you characters a U littler and then Copies them over into the buffer with a very primitive for loop But that's not much of an issue because we want to do that at compile time always so this for loop It looks like We should rather use nameset or something like that No, because what you want to do is that that be executed at compile time And what it does is it fills these Our U string literals members Which look the same like this this block that we need This RTL U string block with a ref count the static flag as I mentioned with the length which we compute from the length of this Literal that we pass in with the string literal and With a buffer that we fill in the constructor with this Expensive looking for you and when we have such a thing such, you know your string literal instance in We'd only data section At runtime then when we want to use it for anything We have a new old string constructor that takes the OU string literal Which is a reference or a pointer to that? block that looks the same as the U string RTL U string block that the OU string actually wants to use and Then we'll use some reinterpreed cast Thus const cast the technical reasons magic To sign its pointers its data member. So this OU string constructor Which is of course not const expo because we want to execute that at runtime. This is very cheap So mission accomplished kind of You stupid reader will have noticed we have an N here all over the place But we don't define that anywhere. So yes, of course This OU string literal class now needs to be a template Because it is parameterized on on the length of the character literal that we pass in so not much of an issue you just add the template thing and Because of Class template argument detection When we actually use Such a no U string literal now We don't need to mention the the value of the Template parameter the length we don't need to write angle brackets of three here because the compiler Can deduce that for us which is Deal breaker here. If we didn't have that All of this would be rather useless because nobody wants to count the Number of characters that is in your string and then for each instance write the right value there So without that being in C++ 17 we wouldn't have improved thing now, but we do and We can nicely now create or change all these Implicitly we changed all these places that use OU string literals Instead of at runtime when assigning them to or using them in the OU string context No longer dynamically creating the memory for them and then copying around the string We have that now in the data section pre-computed and just create pointers to it in the instances so going back to the This was the definition of the OU string literal thing and there's some things Around it that we could if we have C++ 20 something that we could improve the one thing is More of cosmetic thing that We don't need to write out this This for loop to move over or copy the data because in C++ 20 many of the Algorithms in the standard library have evolved into constexpr Functions so that a standard copy Now this is constexpr so you can use it in a constexpr function Copy your data that simplifies this for loop a bit and looks better and the other thing is the combination of replacing the constexpr constructor with a const evolved constructor and dropping the initialization of the buffer so What's that? in C++ 17 Even if you have a constexpr Constructor that assigns to all of the members of this buffer at Before the constructor starts all these All these the variables need to have definite values Instable for for a constexpr thing so we need to we needed to Initialize the buffer to all zeros which is this equals the curly braces that Initializes all the values to zero And then we we override them in the constructor which again looks a bit expensive But of course isn't expensive because all of it happened at compile time Let's see plus plus 20 you no longer need to initialize things upfront But the compiler Takes care to watch what part you have initialized and which parts you haven't So if we Made a mistake somewhere and for example only copied and minus one bytes over Which would mean we would have forgotten to copy over the trailing zero Then this buffer would contain a value for which the last byte or the last duty of 16 Then I would be left uninitialized so Compiler would detect This is something that I cannot do at compile time because it would lead an Uninitialized value and that's not something that is a constant function anymore So because we marked it as cons deval instead of cons expert Compiler has to execute it at compile time So if we ask it to do it at compile time even for a variable that itself is not cons expert just cons If the if the constructor was cons expert It would say okay. I'll do that at runtime and then we would have an uninitialized Trailing byte in there, but if we tell it you must do it at compile time Then it says I can't do that your program is broken. So this is a great thing to detect When you make little mist off by one mistakes here, so yeah, thank you compiler Both by helping us. So what I did with the existing First code is that I made this cons this constructors cons expert for the c++ 17 case and conditionally cons deval for the c++ 20 case that we Would find any any mistakes that we see then they make at least when we compile the c++ 20 And that's it Thank you. Thank you. Am I alone or no, there's somebody We're here Did you want to take any questions? Yes, I guess since there's nothing directly following us So if we have any questions Stephen have you Estimates of what kind of savings there might be from the static stream Yeah, what I did is