high performance C++20 implementation of std::variant

Overview

swl::variant

A minimal compile-time overhead, C++20 implementation of std::variant. Fully standard conforming with a couple of documented differences.

Compile-time performance

Because std::variant is implemented in both GCC and Clang libraries using a simple recursive union, accessing each members result in approximately N^2 functions template instantiations for a variant of size N. This implementation instead use a "binary-tree of unions", resulting in N.log2(N) instantiations, which results in faster compile times (see measurements below).

Run-time performance and binary size

std::variant visit method is usually implemented using a table of functions pointers. Unfortunately, compilers cannot (yet?) "see through" those, and the generated code tends to be much larger and slower than a switch-case equivalent - more on this here. Similarly to Michael Park's implementation, this implementation use a big, recursive switch for visitation.

Testing

The tests come from the LLVM test suite, and are compiled/run by ./tests/all_tests.cpp.

Compile all_tests.cpp as follow :
clang++ -std=c++17 ./test/all_tests.cpp (or compile it as any .cpp)

To run the tests, pass the following arguments to the resulting binary :

  • a string containing a prefix of the command necessary to compile a C++20 file with your compiler of choice...
  • with the root directory and the ./test directory in the include paths...
  • and specifying the output path for compilation of individual tests at the end of the command

For example : ./a.out g++ -std=c++20 -I . -I .. -o ./tmp_test

Some test files succeed by not compiling, so you will see some errors.
(this is a bit spartan, it would be nice to have a cleaner way of running all the tests).

Implementation divergence

  • index() doesn't return a std::size_t, but an integer whose size depends on the numbers of type inside the variant. Basically either unsigned char or unsigned short.

Extensions and customization

  • If you like to live dangerously, swl::unsafe_get behave just like get, but without any errors checking.

  • Two macro based knobs are available :

    • SWL_VARIANT_NO_STD_HASH : this disable the std::hash specializations and avoid the #include , which is big
    • SWL_VARIANT_NO_CONSTEXPR_EMPLACE : this disable constexpr for emplace, and avoid the #include , which is even bigger. Note that this one is an ODR footgun : don't use it if you can't guarantee that it's enabled everywhere in your binaries.

    To use these macros, define them in a file named swl_variant_knobs.hpp, and put it either in the same directory as variant.hpp or at the root of a header search path.

    Both of these are provided to reduce compile times, whether or not this matter depends on your compiler : on my version of Clang, activating both of these macros result in a mere -0.5s, on GCC however, this reduce compile times by more than 4s.

Measurements

The measurements are of the form (compile time, executable file size).

All of these measurements were done without optimizations.

The compilers used were Clang 12 and GCC 10.

Single visitation :

Variant size swl (clang) std (clang) swl (gcc) std (gcc)
20 1s, 50 Ko 1.2s, 80 Ko 4.6s, 50 Ko 1s, 133 Ko
40 1.2s, 120 Ko 2s, 260 Ko 4.8s, 120 Ko 2s, 440 Ko
80 1.4s, 300 Ko 4.6s, 1 Mo 5.3s, 290 Ko 5.7s, 1.8 Mo
160 1.8s, 700 Ko 15s, 4.3 Mo 6s, 720 Ko 21s, 8.2 Mo
320 3s, 1.7 Mo 54s, 22 Mo 8.4s, 1.8 Mo 90s, 40 Mo
640 5s, 4 Mo 250s, 130 Mo 17s, 4.4 Mo 415s, 250 Mo

Multi visitation of some variants of size 10 :

Numbers of variants swl (clang) std (clang) swl (gcc) std (gcc)
2 1.1s, 49 Ko 1.6s, 128 Ko 2.8s, 41 Ko 1.3s, 160 Ko
3 2s, 142 Ko 8s, 1.1 Mo 3.8s, 123 Ko 9s, 1.5 Mo
4 6.7s, 630 Ko 68s, 11 Mo 10.5s, 560 Ko 95s, 17 Mo

Tested compilers

  • GCC 10

Note : Clang 12 will not work (as in : it works only for trivially destructible types).

You might also like...
PHP Encoder, protect PHP scripts in PHP 8 and PHP 7, High Performance, Compitable with X86_64, MIPS, ARM platform and Ubuntu/Centos/OpenWRT system.

What's FRICC2? FRICC2 is a PHP Script encryption tool. When you are developing a commercial software using PHP, the script can be distributed as encry

Diff Match Patch is a high-performance library in multiple languages that manipulates plain text.

The Diff Match and Patch libraries offer robust algorithms to perform the operations required for synchronizing plain text. Diff: Compare two blocks o

Flexible, portable, high-performance bit fields C++ library. unsigned a:13 becomes F13 a;

C-plus-plus-library-bit-fields Flexible, portible, high-performance bit fields C++ library. The bit fields are specified with a dummy structure where

Real Time, High performance BOT detection and protection
Real Time, High performance BOT detection and protection

REAL-TIME BOT PROTECTION CHALLENGE IronFox https://innovera.ir IronFox is a real-time and high performance bot protection, that using Nginx as a reve

Cloud-native high-performance edge/middle/service proxy
Cloud-native high-performance edge/middle/service proxy

Cloud-native high-performance edge/middle/service proxy Envoy is hosted by the Cloud Native Computing Foundation (CNCF). If you are a company that wan

Emergency alert and tracer for realtime high-performance computing app (work in progress, currently supported env is only Linux x86-64).

HPC Emerg Emergency alert and tracer for realtime high-performance computing app (work in progress, currently supported env is only Linux x86-64). Exa

Visualization Library is a C++ middleware for high-performance 2D and 3D graphics applications based on OpenGL 1.x-4.x supporting Windows, Linux and Mac OS X.

Visualization Library 2.2 Gallery About Visualization Library is a C++ middleware for high-performance 2D and 3D graphics applications based on the in

A high performance, shared memory, lock free, cross platform, single file, no dependencies, C++11 key-value store
A high performance, shared memory, lock free, cross platform, single file, no dependencies, C++11 key-value store

SimDB A high performance, shared memory, lock free, cross platform, single file, no dependencies, C++11 key-value store. SimDB is part of LAVA (Live A

A high-performance MongoDB driver for C

mongo-c-driver About mongo-c-driver is a project that includes two libraries: libmongoc, a client library written in C for MongoDB. libbson, a library

Comments
  • Avoid <functional>?

    Avoid ?

    Does the C++ specification allow you to forward-declare the std::hash class template? If so, this would let you specialize it without the need to include <functional>.

    opened by vinniefalco 4
  • Doesn't seem to work w/ CMake's FetchContent?

    Doesn't seem to work w/ CMake's FetchContent?

    I've tried using this the "old" way w/ FetchContent, IE:

    FetchContent_Declare(swl_variant
    	GIT_REPOSITORY "https://github.com/groundswellaudio/swl-variant"
    	GIT_TAG "origin/main"
    	)
    
    FetchContent_GetProperties(swl_variant)
    if(NOT swl_variant_POPULATED)
    	FetchContent_Populate(swl_variant)
    
    	add_subdirectory(${swl_variant_SOURCE_DIR} ${swl_variant_BINARY_DIR})
    endif()
    
    target_link_libraries(MY_TARGET PUBLIC swl_variant)
    

    as well as the "new" way, IE:

    FetchContent_Declare(swl_variant
    	GIT_REPOSITORY "https://github.com/groundswellaudio/swl-variant"
    	GIT_TAG "origin/main"
    	)
    	
    FetchContent_MakeAvailable(swl_variant)
    
    target_link_libraries(MY_TARGET PUBLIC swl_variant)
    

    and neither are working (swl/variant.hpp isn't found when trying to #include it)

    I've also tried adding ${swl_variant_INCLUDE_DIRS} to my target_include_directories but still no dice.

    Don't get any errors from CMake, CMake version is 3.23.2

    opened by braxtons12 1
Owner
groundswell everything
null
A cleaner and more intuitive std::variant alternative

[WIP] ExtendedVariant This single header library is part of my C++ extended standard stdex libraries. Check our my profile for more. Working with C++

pinsrq 3 Jun 13, 2021
Invoke.hpp - std::invoke/std::apply analogs for C++11/14

invoke.hpp std::invoke/std::apply analogs for C++11/14 Requirements gcc >= 4.9 clang >= 3.8 msvc >= 2015 Installation invoke.hpp is a header-only libr

Matvey Cherevko 33 Dec 1, 2022
An eventing framework for building high performance and high scalability systems in C.

NOTE: THIS PROJECT HAS BEEN DEPRECATED AND IS NO LONGER ACTIVELY MAINTAINED As of 2019-03-08, this project will no longer be maintained and will be ar

Meta Archive 1.7k Dec 14, 2022
EDK2 port for Lumia 630 & it's 512mb variants. 1gb variant coming soon.

Lumia930Pkg WIP Custom ARM UEFI firmware for Lumia930 Current Status EMMC MMU PMIC GPIO Working Linux Notes Linux kernel do boots but crashes pretty s

Fiery 0 Jan 2, 2022
Any - A simple variant type for C++

ANY Variant type for C++ This is similar to Boost.Any in that any type can be encapsulated and retrieved, but this implementation does not have any de

Paul Howes 9 Oct 24, 2020
Implementation of the (not yet written) std::experimental::rational proposal.

Rational Implementation of the (not yet written) std::experimental::rational proposal. Getting started Copy include/std/experimental/rational.hpp to y

Ali Can Demiralp 9 Nov 18, 2022
High performance C++11 signals

High performance C++11 signals See Performance of a C++11 Signal System for the original source code, as well as performance measurements compared to

Lars Pensjö 145 Nov 28, 2022
A C++11 large integer library with effective high performance, simplistic in nature and also clean in the eyes.

BigIntegerCPP BigIntegerCPP is a C++11 port of large integer library used in CryptoLib4Pascal. It allows mostly parsing of numbers as strings in diffe

Telepati 26 Dec 22, 2022
High Performance Streams Based on Coroutine TS ⚡

Conduit ⚡ Lazy High Performance Streams using Coroutine TS Conduit is a utility library for building and transforming, ranges and lazy (infinite) iter

LoopPerfect 144 Dec 3, 2022
Convenient, high-performance RGB color and position control for console output

Oof (omnipotent output friend) It's common for C++ programs to write output to the console. But consoles are far more capable than what they are usual

Sebastian Werhausen 776 Dec 27, 2022