From: Greg Burri Date: Wed, 20 Jan 2021 09:55:20 +0000 (+0100) Subject: First commit X-Git-Url: https://git.euphorik.ch/?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=cpp_sandbox.git First commit --- 7057d5a403954e0a7a7eb3b4e9181989294a3436 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ee5385 --- /dev/null +++ b/.gitignore @@ -0,0 +1,362 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd diff --git a/Sandbox.sln b/Sandbox.sln new file mode 100644 index 0000000..7e1b256 --- /dev/null +++ b/Sandbox.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sandbox", "Sandbox\Sandbox.vcxproj", "{1642C97D-ED86-4894-A9A9-0A2F265DBCDB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Debug|x64.ActiveCfg = Debug|x64 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Debug|x64.Build.0 = Debug|x64 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Debug|x86.ActiveCfg = Debug|Win32 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Debug|x86.Build.0 = Debug|Win32 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Release|x64.ActiveCfg = Release|x64 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Release|x64.Build.0 = Release|x64 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Release|x86.ActiveCfg = Release|Win32 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {63BADAE9-45C6-45B3-9459-7911368E2F07} + EndGlobalSection +EndGlobal diff --git a/Sandbox/AggregateInitializations.cpp b/Sandbox/AggregateInitializations.cpp new file mode 100644 index 0000000..02be415 --- /dev/null +++ b/Sandbox/AggregateInitializations.cpp @@ -0,0 +1,25 @@ +#include "AggregateInitializations.h" + +#include +using namespace std; + +namespace AggregateInitializations +{ + struct B + { + double q; + }; + + struct S : B + { + int i; + float f; + }; + +} + +void AggregateInitializations::tests() +{ + S s{ {42.123}, 1, 2.32f }; // Initialization of base class. + cout << "s.q = " << s.q << endl; +} \ No newline at end of file diff --git a/Sandbox/AggregateInitializations.h b/Sandbox/AggregateInitializations.h new file mode 100644 index 0000000..48a939e --- /dev/null +++ b/Sandbox/AggregateInitializations.h @@ -0,0 +1,8 @@ +#pragma once + + +namespace AggregateInitializations +{ + void tests(); +}; + diff --git a/Sandbox/Bind.cpp b/Sandbox/Bind.cpp new file mode 100644 index 0000000..0724834 --- /dev/null +++ b/Sandbox/Bind.cpp @@ -0,0 +1,57 @@ +#include "Bind.h" + +#include +#include +using namespace std; + +// https://en.cppreference.com/w/cpp/utility/functional/bind +// Ep 15: https://www.youtube.com/watch?v=JtUZmkvroKg & https://www.youtube.com/watch?v=ZlHi8txU4aQ + +namespace Bind +{ + template + void print(T i, const string& s) + { + cout << i << ' ' << s << endl; + } + + void bind() + { + int i = 5; + + // The given function must be a concrete one (the generic parameter of 'print' must be specified in this case). + // 'ref' is to create a standard reference to 'i'. + // the second parameter create a parameter in the new created function. + // 'bind' were originaly from the Boost library. + const auto f = bind(&print, ref(i), placeholders::_1); + + f("Hello"); + + i = 6; + f(", World"); + + function f2(f); // Create a 'std::function'. + i = 7; + f2("!"); + } + + // Prefer lambdas instead of bind. + void lambda() + { + // Swapping arguments. + const auto f = [](auto&& arg1, auto&& arg2) + { + // Perfect forwarding (not necessary). + print(forward(arg2), forward(arg1)); + }; + + f("Hello", 42); + } +} + +void Bind::tests() +{ + Bind::bind(); + cout << "-----" << endl; + Bind::lambda(); +} \ No newline at end of file diff --git a/Sandbox/Bind.h b/Sandbox/Bind.h new file mode 100644 index 0000000..f62ce59 --- /dev/null +++ b/Sandbox/Bind.h @@ -0,0 +1,7 @@ +#pragma once + +namespace Bind +{ + void tests(); +}; + diff --git a/Sandbox/Concepts.cpp b/Sandbox/Concepts.cpp new file mode 100644 index 0000000..3e75c9b --- /dev/null +++ b/Sandbox/Concepts.cpp @@ -0,0 +1,67 @@ +#include "Concepts.h" + +#include +#include +#include +#include +#include +#include +using namespace std; + +// From: "Demo Zoo: Zero Cost Abstractions in C++20, Rust, & Zig": https://www.youtube.com/watch?v=43X9ia-qpds + +namespace Concepts +{ + template + using Scalar = std::decay_t; + + template + concept FloatVec = + std::floating_point> && + requires(Vec vec) + { + { vec.size() } -> std::integral; + }; + + template + auto norm(Vec vec) -> Scalar // Should be 'norm(const Vec& vec)' but it doesn't work with VS 2019 16.6.3. + { + using Index = decltype(vec.size()); + Scalar result = 0; + for (Index i = 0; i < vec.size(); i += 1) + { + result += vec[i] * vec[i]; + } + return std::sqrt(result); + } + + struct Point2 + { + float x = 0; + float y = 0; + + auto size() -> int { + return 2; + } + + auto operator[](int i) const -> float { + return i == 0 ? x : y; + } + }; + + float norm2(float x, float y) + { + return norm(Point2{ x, y }); + } + + double norm_nd(const std::vector& a) + { + return norm(a); + } +} + +void Concepts::tests() +{ + cout << "norm: " << norm_nd({ 1, 2, 3 }) << endl; + cout << "norm: " << norm2(3, 4) << endl; +} diff --git a/Sandbox/Concepts.h b/Sandbox/Concepts.h new file mode 100644 index 0000000..84d756f --- /dev/null +++ b/Sandbox/Concepts.h @@ -0,0 +1,7 @@ +#pragma once + +namespace Concepts +{ + void tests(); +}; + diff --git a/Sandbox/ConstexprIf.cpp b/Sandbox/ConstexprIf.cpp new file mode 100644 index 0000000..f34d090 --- /dev/null +++ b/Sandbox/ConstexprIf.cpp @@ -0,0 +1,44 @@ +#include "ConstexprIf.h" + +#include +#include +#include +using namespace std; + +// Ep 18: https://www.youtube.com/watch?v=qHgM5UdzPQU + +namespace ConstexprIf +{ + template + constexpr bool is_integral_has_a_big_max_limit() + { + if constexpr (is_integral::value && !is_same::value) // Because 'bool' is an integral type. + { + // Here we can use a '&&' to put this condition in the first 'if' because template do not use short-cirtcuit boolean operators. + if constexpr (numeric_limits::max() > numeric_limits::max()) + return true; + } + + return false; + } + + template + auto print_type_info(const T& v) + { + if constexpr (is_integral_has_a_big_max_limit()) + return v + 1; + else if constexpr (is_floating_point::value) + return v + 0.1; + else + return v; + } +} + +void ConstexprIf::tests() +{ + cout << print_type_info(5) << endl; + cout << print_type_info(5LL) << endl; + cout << print_type_info(2.3) << endl; + cout << print_type_info("hello") << endl; + cout << print_type_info(true) << endl; +} \ No newline at end of file diff --git a/Sandbox/ConstexprIf.h b/Sandbox/ConstexprIf.h new file mode 100644 index 0000000..605228b --- /dev/null +++ b/Sandbox/ConstexprIf.h @@ -0,0 +1,7 @@ +#pragma once + +namespace ConstexprIf +{ + void tests(); +}; + diff --git a/Sandbox/CostOfUsingStatic.cpp b/Sandbox/CostOfUsingStatic.cpp new file mode 100644 index 0000000..d6134a1 --- /dev/null +++ b/Sandbox/CostOfUsingStatic.cpp @@ -0,0 +1,44 @@ +#include "CostOfUsingStatic.h" + +#include +using namespace std; + +// From: https://www.youtube.com/watch?v=B3WWsKFePiM + +namespace CostOfUsingStatic +{ + struct C + { + // This call is costy. + static const string& magic_static() + { + // Static variables are very costly. + // Each time a thread safe comparison must be executed. + static const string s = "bob"; + return s; + } + + const string& s = magic_static(); + + const string& magic_static_ref() + { + return s; + } + }; +} + +void CostOfUsingStatic::tests() +{ + C c; + size_t total_size = 0; + + for (int i = 0; i < 2000000000; ++i) + { + total_size += c.magic_static_ref().size() + i; // It takes ~500 ms. + //total_size += C::magic_static().size() + i; // It takes ~1200 ms. + } + + //return total_size; + + cout << "total size: " << total_size << endl; +} \ No newline at end of file diff --git a/Sandbox/CostOfUsingStatic.h b/Sandbox/CostOfUsingStatic.h new file mode 100644 index 0000000..7492e15 --- /dev/null +++ b/Sandbox/CostOfUsingStatic.h @@ -0,0 +1,7 @@ +#pragma once + +namespace CostOfUsingStatic +{ + void tests(); +} + diff --git a/Sandbox/DefaultMethods.cpp b/Sandbox/DefaultMethods.cpp new file mode 100644 index 0000000..aea349c --- /dev/null +++ b/Sandbox/DefaultMethods.cpp @@ -0,0 +1,99 @@ +#include "DefaultMethods.h" + +#include +using namespace std; + +namespace DefaultMethods +{ + class C + { + int a; + + public: + // Default constructor (here we remove the default one). + C() = delete; + + // Copy constructor. + C(const C& other); + + // Move constructor. + C(C&& other) noexcept; + + // A custom constructor. + C(int a); + + // Copy-assignment operator. + C& operator=(const C& other); + + // Move-assignment operator. + C& operator=(C&& other) noexcept; + + ~C() noexcept; + + int getA(); + }; + + C::C(const C& other) + { + cout << "Copy ctor, other.a = " << other.a << endl; + this->a = other.a; + } + + C::C(C&& other) noexcept + { + cout << "Move ctor, other.a = " << other.a << endl; + this->a = other.a; + other.a = 0; + } + + C::C(int a) + : a{ a } + { + cout << "ctor, a = " << a << endl; + } + + C& C::operator=(const C& other) + { + cout << "Copy assignment operator" << endl; + this->a = other.a; + return *this; + } + + C& C::operator=(C&& other) noexcept + { + cout << "Move assignment operator" << endl; + this->a = other.a; + other.a = 0; + return *this; + } + + C::~C() noexcept + { + cout << "Destructor, a = " << this->a << endl; + } + + int C::getA() + { + return this->a; + } +} + +void DefaultMethods::tests() +{ + // Use of universal initialization. + C c1{ 42 }; + + C c2 = move(c1); // Force to treat 'c1' as a right-hand value. + C c3{ c1 }; + C c4{ 42 }; + cout << "c1.a = " << c1.getA() << endl; + cout << "c2.a = " << c2.getA() << endl; + cout << "c3.a = " << c3.getA() << endl; + cout << "c4.a = " << c4.getA() << endl; + + cout << "--- copy some values" << endl; + c1 = c2; + c2 = C{ 321 }; + cout << "c1.a = " << c1.getA() << endl; + cout << "c2.a = " << c2.getA() << endl; +} \ No newline at end of file diff --git a/Sandbox/DefaultMethods.h b/Sandbox/DefaultMethods.h new file mode 100644 index 0000000..c7f5459 --- /dev/null +++ b/Sandbox/DefaultMethods.h @@ -0,0 +1,8 @@ +#pragma once + +namespace DefaultMethods +{ + void tests(); +} + + diff --git a/Sandbox/FoldExpressions.cpp b/Sandbox/FoldExpressions.cpp new file mode 100644 index 0000000..01c861e --- /dev/null +++ b/Sandbox/FoldExpressions.cpp @@ -0,0 +1,42 @@ +#include "FoldExpressions.h" + +#include +using namespace std; + + +// Ep 20: https://www.youtube.com/watch?v=nhk8pF_SlTk +// https://en.cppreference.com/w/cpp/language/fold + +namespace FoldExpressions +{ + // Old fashion (before C++17). + template + auto sum(T ... t) + { + typename common_type::type result{}; + initializer_list{ (result += t, 0)... }; + return result; + } + + // With C++17. + template + auto sum2(T ... t) + { + const double n = 5; + return (5 + ... + t); + } + + template + auto avg(T ... t) + { + return (t + ...) / sizeof...(t); + } +} + +void FoldExpressions::tests() +{ + cout << sum(1, 2.2, 3, 4, 5) << endl; + cout << sum2(1, 2.2, 3, 4, 5) << endl; + + cout << avg(1, 2.2, 3, 4, 5) << endl; +} \ No newline at end of file diff --git a/Sandbox/FoldExpressions.h b/Sandbox/FoldExpressions.h new file mode 100644 index 0000000..68859f9 --- /dev/null +++ b/Sandbox/FoldExpressions.h @@ -0,0 +1,7 @@ +#pragma once + +namespace FoldExpressions +{ + void tests(); +}; + diff --git a/Sandbox/FunctionsAsTemplate.cpp b/Sandbox/FunctionsAsTemplate.cpp new file mode 100644 index 0000000..efa13af --- /dev/null +++ b/Sandbox/FunctionsAsTemplate.cpp @@ -0,0 +1,34 @@ +#include "FunctionsAsTemplate.h" + +#include +#include +using namespace std; + +#include "Types.h" + +namespace FunctionsAsTemplate +{ + template + i64 memoize(i64 x) + { + static std::map cache; + auto i = cache.find(x); + if (i != cache.end()) + return i->second; + else + return cache[x] = f(x); + } + + i64 fib(i64 n) { + if (n < 2) + return n; + else + return memoize(n - 1) + memoize(n - 2); + } +} + +void FunctionsAsTemplate::tests() +{ + i64 n = 80; + cout << "fib(" << n << ") = " << fib(n) << endl; +} \ No newline at end of file diff --git a/Sandbox/FunctionsAsTemplate.h b/Sandbox/FunctionsAsTemplate.h new file mode 100644 index 0000000..53bb3ac --- /dev/null +++ b/Sandbox/FunctionsAsTemplate.h @@ -0,0 +1,7 @@ +#pragma once + +namespace FunctionsAsTemplate +{ + void tests(); +} + diff --git a/Sandbox/IfAndSwitchInitStatements.cpp b/Sandbox/IfAndSwitchInitStatements.cpp new file mode 100644 index 0000000..3217c83 --- /dev/null +++ b/Sandbox/IfAndSwitchInitStatements.cpp @@ -0,0 +1,54 @@ +#include "IfAndSwitchInitStatements.h" + +#include +#include +#include +using namespace std; + +// Ep 21: https://www.youtube.com/watch?v=AiXU5EuLZgc + +namespace IfAndSwitchInitStatements +{ + vector make_vec() + { + return { 1, 2, 3, 4 }; + } +} + +void IfAndSwitchInitStatements::tests() +{ + auto vec = make_vec(); + + // Same for 'switch' block. + if (const auto itr = find(vec.begin(), vec.end(), 2); + itr != vec.end()) + { + *itr = 42; + } + else + { + vec.push_back(42); + } + + // Declare an variable into a if condition allows to use this variable only in the if scope + // and will not get out of scope. + // Here we can reuse the name 'itr' previously used in the previous if statement. + if (const auto itr = find(vec.begin(), vec.end(), 3); + itr != vec.end()) + { + *itr = 43; + } + else + { + vec.push_back(43); + } + + for (auto i = vec.begin(); i != vec.end(); ++i) + { + if (i != vec.begin()) + cout << ", "; + cout << *i; + } + + cout << endl; +} \ No newline at end of file diff --git a/Sandbox/IfAndSwitchInitStatements.h b/Sandbox/IfAndSwitchInitStatements.h new file mode 100644 index 0000000..6b10980 --- /dev/null +++ b/Sandbox/IfAndSwitchInitStatements.h @@ -0,0 +1,7 @@ +#pragma once + +namespace IfAndSwitchInitStatements +{ + void tests(); +}; + diff --git a/Sandbox/Lambdas.cpp b/Sandbox/Lambdas.cpp new file mode 100644 index 0000000..c7a265f --- /dev/null +++ b/Sandbox/Lambdas.cpp @@ -0,0 +1,124 @@ +#include "Lambdas.h" + +#include +#include +#include +#include +#include +#include +using namespace std; + +// Ep 32: https://www.youtube.com/watch?v=_CbBfuQQQI8 +// Ep 37: https://www.youtube.com/watch?v=_1X9D8Z5huA +// Ep 40: https://www.youtube.com/watch?v=W-xTpqj31mI, not shown here, see 'VariadicUsing.cpp'. +// Ep 41: https://www.youtube.com/watch?v=kmza9U_niq4 (constexpr Lambda Support) +// Ep 49: https://www.youtube.com/watch?v=3wm5QzdddYc (Why Inherit From Lambdas?) + +namespace Lambdas +{ + // Identical to the lambda [](){ return 5; }. + struct Lambda + { + auto operator()() const + { + return 5; + } + }; + + ///// + + struct Color + { + uint8_t num; + uint8_t r; + uint8_t g; + uint8_t b; + double luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; + }; + + ostream& operator<<(ostream& stream, const Color& color) + { + stream << "{ num = " << int(color.num) << ", r = " << int(color.r) << ", g = " << int(color.g) << ", b = " << int(color.b) << "}"; + return stream; + } + + template + constexpr auto nearest_color(const Colors& colors, const uint8_t r, const uint8_t g, const uint8_t b) + { + return + *min_element( + begin(colors), + end(colors), + // Lambda in constexpr. + [r, g, b](const auto& lhs, const auto& rhs) + { + const auto square = [](auto t) { return t * t; }; + return + square(lhs.r - r) + square(lhs.g - g) + square(lhs.b - b) < + square(rhs.r - r) + square(rhs.g - g) + square(rhs.b - b); + } + ); + } + + ///// + + // Merge types with subtyping. + template + struct Visitor : B... + { + template + Visitor(T&& ... t) : B(forward(t))... + { + } + }; + + // Class template argument deduction: https://en.cppreference.com/w/cpp/language/class_template_argument_deduction + template + Visitor(T...) -> Visitor...>; +} + +void Lambdas::tests() +{ + // Parameter parenthesis can be omitted. + cout << [] { return 5; }() << endl; + + cout << "/////" << endl; + ///// + + // Stateful lambda as a fibonnacci sequence. + auto l = [i = 0, j = 1]() mutable + { + i = exchange(j, j + i); + return i; + }; + + for (int i = 0; i < 10; i++) + cout << l() << endl; + + cout << "/////" << endl; + ///// + + vector colors{ Color { 1, 10, 50, 200 }, Color { 2, 40, 10, 100 } , Color { 3, 250, 0, 70 } }; + auto c = nearest_color(colors, 20, 40, 60); + cout << "color: " << c << endl; + + cout << "/////" << endl; + ///// + + // Array of doubles and ints. + const auto aString{ "XYZ"s }; + array, 6> a{ "ABC", 13.2, 3, 6.8, aString, 7 }; + + int intTotal = 0; + double doubleTotal = 0.0; + string allStrings; + Visitor visitor{ + [&intTotal](const int i) { intTotal += i; }, + [&doubleTotal](const double d) { doubleTotal += d; }, + [&allStrings](const string& s) { allStrings.append(s); } + }; + + for_each(begin(a), end(a), [&visitor](const auto& v) { visit(visitor, v); }); + + cout << "intTotal = " << intTotal << ", doubleTotal = " << doubleTotal << ", allStrings = " << allStrings << endl; +} diff --git a/Sandbox/Lambdas.h b/Sandbox/Lambdas.h new file mode 100644 index 0000000..d7ad8d7 --- /dev/null +++ b/Sandbox/Lambdas.h @@ -0,0 +1,7 @@ +#pragma once + +namespace Lambdas +{ + void tests(); +}; + diff --git a/Sandbox/NextAndExchange.cpp b/Sandbox/NextAndExchange.cpp new file mode 100644 index 0000000..a08af8e --- /dev/null +++ b/Sandbox/NextAndExchange.cpp @@ -0,0 +1,23 @@ +#include "NextAndExchange.h" + +#include +#include +#include +using namespace std; + +namespace NextAndExchange +{ + +} + +void NextAndExchange::tests() +{ + // 'next'. + vector v{ 42, 420, 2, 3, 4, 5, 6, 7 }; + cout << "Is the list sorted? " << is_sorted(next(v.begin()), v.end()) << endl; + + // 'exchange'. + auto a = 1; + auto b = exchange(a, 2); + cout << "a = " << a << ", b = " << b << endl; +} \ No newline at end of file diff --git a/Sandbox/NextAndExchange.h b/Sandbox/NextAndExchange.h new file mode 100644 index 0000000..192dc0d --- /dev/null +++ b/Sandbox/NextAndExchange.h @@ -0,0 +1,7 @@ +#pragma once + +namespace NextAndExchange +{ + void tests(); +} + diff --git a/Sandbox/PointerToMember.cpp b/Sandbox/PointerToMember.cpp new file mode 100644 index 0000000..35eb1f0 --- /dev/null +++ b/Sandbox/PointerToMember.cpp @@ -0,0 +1,33 @@ +#include "PointerToMember.h" + +#include +using namespace std; + +namespace PointerToMember +{ + struct Test { + int num; + + Test(int n) + { + this->num = n; + } + + void func() + { + cout << "func called, this->num = " << this->num << endl; + } + }; + + int Test::* ptr_num = &Test::num; // Pointer to a field of 'Test'. + void (Test::* ptr_func)() = &Test::func; // Pointer to a method of 'Test'. +} + +void PointerToMember::tests() +{ + Test t{ 42 }; + Test* pt = new Test{ 420 }; + + (t.*ptr_func)(); + (pt->*ptr_func)(); +} \ No newline at end of file diff --git a/Sandbox/PointerToMember.h b/Sandbox/PointerToMember.h new file mode 100644 index 0000000..5166cba --- /dev/null +++ b/Sandbox/PointerToMember.h @@ -0,0 +1,7 @@ +#pragma once + +namespace PointerToMember +{ + void tests(); +} + diff --git a/Sandbox/ReadVarint.cpp b/Sandbox/ReadVarint.cpp new file mode 100644 index 0000000..52ebddd --- /dev/null +++ b/Sandbox/ReadVarint.cpp @@ -0,0 +1,107 @@ +#include "ReadVarint.h" + +#include +using namespace std; + +// 'varint' is a way to encode integer in a variable number of byte. Using for serializing for example. +// Partial implementation of https://developers.google.com/protocol-buffers/docs/encoding + +namespace ReadVarint +{ + void readUInt(const uint8_t*& p, uint32_t res, uint32_t& result) + { + for (uint32_t i = 2; i < 5; i++) + { + uint32_t byte = static_cast(p[i]); + res += (byte - 1) << (7 * i); + if (byte < 128) + { + p += (size_t)i + 1; + result = res; + return; + } + } + + for (uint32_t i = 5; i < 10; i++) + { + uint32_t byte = static_cast(p[i]); + if (byte < 128) + { + p += (size_t)i + 1; + result = res; + return; + } + } + + result = res; + } + + void readUInt(const uint8_t*& p, uint32_t res32, uint64_t& result) + { + uint64_t res = res32; + for (uint32_t i = 2; i < 10; i++) + { + uint64_t byte = static_cast(p[i]); + res += (byte - 1) << (7 * i); + if (byte < 128) + { + p += (size_t)i + 1; + result = res; + return; + } + } + + result = 0; + } + + template + T readUInt(const uint8_t*& p) + { + p += 1; // Skip the first byte (type + field n°) + + uint32_t res = p[0]; + if (!(res & 0x80)) + { + p += 1; + return res; + } + + uint32_t byte = p[1]; + res += (byte - 1) << 7; + if (!(byte & 0x80)) + { + p += 2; + return res; + } + + T result; + readUInt(p, res, result); + return result; + } +} + +void ReadVarint::tests() +{ + const uint8_t bytes[] = { + 0x08, 0x03, // v1 = 3. + 0x10, 0xdf, 0xd0, 0x03, // v2 = 59487. + + 0x1a, 0x0a, // v3 = 10. + + 0x20, 0xb7, 0xac, 0xe5, 0x85, 0x08, 0x28, // v4 = 2159629879 + + 0xb4, 0xdb, 0x9b, 0xf0, 0xe6, 0x97, 0xb8, 0xc1, 0x59, 0x38 // v5 = 6449964724842327476 + }; + + const uint8_t* p = bytes; // Pointer on const bytes. + + auto v1 = readUInt(p); + auto v2 = readUInt(p); + auto v3 = readUInt(p); + auto v4 = readUInt(p); + auto v5 = readUInt(p); + + cout << "p = " << hex << (int)(*p) << dec << endl; + + cout << "v1 = " << v1 << ", v2 = " << v2 << ", v3 = " << v3 << ", v4 = " << v4 << ", v5 = " << v5<< endl; +} \ No newline at end of file diff --git a/Sandbox/ReadVarint.h b/Sandbox/ReadVarint.h new file mode 100644 index 0000000..7479f30 --- /dev/null +++ b/Sandbox/ReadVarint.h @@ -0,0 +1,7 @@ +#pragma once + +namespace ReadVarint +{ + void tests(); +}; + diff --git a/Sandbox/Sandbox.vcxproj b/Sandbox/Sandbox.vcxproj new file mode 100644 index 0000000..ba3e26b --- /dev/null +++ b/Sandbox/Sandbox.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {1642C97D-ED86-4894-A9A9-0A2F265DBCDB} + Win32Proj + Sandbox + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + + + Console + true + + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + + + Console + true + + + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sandbox/Sandbox.vcxproj.filters b/Sandbox/Sandbox.vcxproj.filters new file mode 100644 index 0000000..2e56606 --- /dev/null +++ b/Sandbox/Sandbox.vcxproj.filters @@ -0,0 +1,129 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Sandbox/TemplateMetaProgramming.cpp b/Sandbox/TemplateMetaProgramming.cpp new file mode 100644 index 0000000..a54fb3c --- /dev/null +++ b/Sandbox/TemplateMetaProgramming.cpp @@ -0,0 +1,55 @@ +#include "TemplateMetaProgramming.h" + +#include +#include +#include +using namespace std; + +#include "Types.h" + +// See chapter 28 of "The C++ programming language". + +namespace TemplateMetaProgramming +{ + template + struct Fib + { + static const i64 val = Fib::val + Fib::val; + }; + + template<> + struct Fib<0> + { + static const i64 val = 0; + }; + + template<> + struct Fib<1> + { + static const i64 val = 1; + }; + + ///// + + template + i64 fib_impl(integer_sequence, const i64 i) + { + constexpr array a = { Fib::val... }; + return a[i]; + } + + i64 fib(const i64 i) + { + // Generate all fibonacci sequence from 0 to 80. + return fib_impl(make_integer_sequence(), i); + } +} + +void TemplateMetaProgramming::tests() +{ + constexpr i64 n = 80; + cout << "Compile time: fib(" << n << ") = " << Fib::val << endl; + + const i64 m = 80; + cout << "Run time: fib(" << m << ") = " << fib(m) << endl; +} \ No newline at end of file diff --git a/Sandbox/TemplateMetaProgramming.h b/Sandbox/TemplateMetaProgramming.h new file mode 100644 index 0000000..1a68459 --- /dev/null +++ b/Sandbox/TemplateMetaProgramming.h @@ -0,0 +1,7 @@ +#pragma once + +namespace TemplateMetaProgramming +{ + void tests(); +} + diff --git a/Sandbox/Traits.cpp b/Sandbox/Traits.cpp new file mode 100644 index 0000000..066138c --- /dev/null +++ b/Sandbox/Traits.cpp @@ -0,0 +1,46 @@ +#include "Traits.h" + +#include +#include + +using namespace std; + +namespace Traits +{ + class C {}; + + ///// + + void algorithm_signed(int i) { /* [..] */ cout << "process a signed integer" << endl; } + void algorithm_unsigned(unsigned) { /* [..] */ cout << "process an unsigned integer" << endl; } + + template + void algorithm(T t) + { + if constexpr (is_signed::value) + algorithm_signed(t); + else if constexpr (is_unsigned::value) + algorithm_unsigned(t); + else + static_assert(is_signed::value || is_unsigned::value, "Must be signed or unsigned"); + } + + ///// + + template + typename remove_reference::type&& move(T&& arg) + { + return static_cast::type&&>(arg); + } +} + +void Traits::tests() +{ + cout << "Is the type 'C' a floating point?: " << is_floating_point::value << endl; + cout << "Is the type 'float' a floating point?: " << is_floating_point::value << endl; + cout << "Is the type 'int' a floating point?:" << is_floating_point::value << endl; + + algorithm(3); + algorithm(3U); + // algorithm("hello"); Do not compile. +} diff --git a/Sandbox/Traits.h b/Sandbox/Traits.h new file mode 100644 index 0000000..41f7e74 --- /dev/null +++ b/Sandbox/Traits.h @@ -0,0 +1,12 @@ +#pragma once + +/* +Type traits: conditional compilation based on generic type properties. Subset of template metaprogramming. + +From: https://www.internalpointers.com/post/quick-primer-type-traits-modern-cpp +*/ + +namespace Traits +{ + void tests(); +} \ No newline at end of file diff --git a/Sandbox/Types.h b/Sandbox/Types.h new file mode 100644 index 0000000..bac6e1f --- /dev/null +++ b/Sandbox/Types.h @@ -0,0 +1,5 @@ +#pragma once + +using namespace std; + +using i64 = conditional_t; \ No newline at end of file diff --git a/Sandbox/VariadicTemplates.cpp b/Sandbox/VariadicTemplates.cpp new file mode 100644 index 0000000..86bdef2 --- /dev/null +++ b/Sandbox/VariadicTemplates.cpp @@ -0,0 +1,114 @@ +#include "VariadicTemplates.h" + +#include +#include +using namespace std; + +// Introduction to C++ Variadic Templates: https://kevinushey.github.io/blog/2016/01/27/introduction-to-c++-variadic-templates/ +// Using Variadic Templates cleanly: https://florianjw.de/en/variadic_templates.html +// Variadic templates in C++ : https://eli.thegreenplace.net/2014/variadic-templates-in-c/ + +namespace VariadicTemplates +{ + template // Template parameter pack: multiple types (0 type can be given). + void ignore(Ts ... ts) + { + } + + template + double sum(T t) + { + return t; + } + template + double sum(T t, Ts ... ts) + { + return t + sum(ts...); + } + + template + T square(T t) + { + return t * t; + } + template + double power_sum(T t) + { + return t; + } + template + double power_sum(T t, Ts ... ts) + { + return t + power_sum(square(ts)...); + } + + ///// + + struct S + { + S(int a, double b) + : a(a), b(b) + { + cout << "Ctor" << endl; + } + + S(const S& other) + : a(other.a), b(other.b) + { + cout << "Copy ctor" << endl; + } + + // This move ctor isn't necessary because it does the same thing as the copy ctor. + S(S&& other) noexcept + : a(other.a), b(other.b) + { + cout << "Move ctor" << endl; + } + + const int a; + const double b; + }; + + ostream& operator<<(ostream& os, const S& s) + { + os << "{ a = " << s.a << ", b = " << s.b << "}"; + return os; + } + + ///// + + template + void ignore_return_values(Ts&&...) {} + + template + void increment_all(Ts& ... values) + { + ignore_return_values((++values)...); + } +} + +void VariadicTemplates::tests() +{ + ignore(1, 2.0, true); // Types can be different. + + cout << sum(1, 2, 3, 4) << endl; + cout << power_sum(1, 2, 3, 4) << endl; + + ///// + + vector v; + // 'emplace_back' use variadic template. + v.emplace_back(1, 1.5); + v.emplace_back(2, 1.6); + v.emplace_back(3, 1.7); + + for (const auto& i : v) + cout << "element: " << i << endl; + + ///// + + int i = 3; + double d = 4.5; + increment_all(i, d); + cout << i << ", " << d << endl; +} \ No newline at end of file diff --git a/Sandbox/VariadicTemplates.h b/Sandbox/VariadicTemplates.h new file mode 100644 index 0000000..232640b --- /dev/null +++ b/Sandbox/VariadicTemplates.h @@ -0,0 +1,7 @@ +#pragma once + +namespace VariadicTemplates +{ + void tests(); +}; + diff --git a/Sandbox/VariadicUsing.cpp b/Sandbox/VariadicUsing.cpp new file mode 100644 index 0000000..b87884a --- /dev/null +++ b/Sandbox/VariadicUsing.cpp @@ -0,0 +1,37 @@ +#include "VariadicUsing.h" + +#include +using namespace std; + +// Ep 48: https://www.youtube.com/watch?v=1gNzhE-Tn40 + +namespace VariadicUsing +{ + template + struct Merged : B... + { + template + Merged(T&& ... t) : B(forward(t))... + { + } + + using B::operator()...; // It seems not necessary. + }; + + // Class template argument deduction: https://en.cppreference.com/w/cpp/language/class_template_argument_deduction. + template + Merged(T...) -> Merged...>; +} + +void VariadicUsing::tests() +{ + // Lambda are standard type. + const auto l1 = []() { return 4; }; + const auto l2 = [](const int i) { return i * 10; }; + + Merged merged(l1, l2, [](const double d) { return d * 3.2; }); + + cout << merged() << endl; + cout << merged(10) << endl; + cout << merged(10.5) << endl; +} diff --git a/Sandbox/VariadicUsing.h b/Sandbox/VariadicUsing.h new file mode 100644 index 0000000..7541dd3 --- /dev/null +++ b/Sandbox/VariadicUsing.h @@ -0,0 +1,7 @@ +#pragma once + +namespace VariadicUsing +{ + void tests(); +}; + diff --git a/Sandbox/main.cpp b/Sandbox/main.cpp new file mode 100644 index 0000000..9ecb8e9 --- /dev/null +++ b/Sandbox/main.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +using namespace std; + +#include "DefaultMethods.h" +#include "Traits.h" +#include "PointerToMember.h" +#include "FunctionsAsTemplate.h" +#include "CostOfUsingStatic.h" +#include "TemplateMetaProgramming.h" +#include "NextAndExchange.h" +#include "Bind.h" +#include "ConstexprIf.h" +#include "FoldExpressions.h" +#include "IfAndSwitchInitStatements.h" +#include "AggregateInitializations.h" +#include "VariadicUsing.h" +#include "VariadicTemplates.h" +#include "Lambdas.h" +#include "ReadVarint.h" +#include "Concepts.h" + +constexpr auto DEFAULT_METHODS_ENABLED = false; +constexpr auto TRAITS_ENABLED = false; +constexpr auto POINTER_TO_MEMBER = false; +constexpr auto FUNCTIONS_AS_TEMPLATE = false; +constexpr auto COST_OF_USING_STATIC = false; +constexpr auto TEMPLATE_METAPROGRAMMING = false; +constexpr auto NEXT_AND_EXCHANGE = false; +constexpr auto BIND = false; +constexpr auto CONSTEXPR_IF = false; +constexpr auto FOLD_EXPRESSIONS = false; +constexpr auto IF_AND_SWITCH_INIT_STATEMENTS = false; +constexpr auto AGGREGATE_INITIALIZATIONS = false; +constexpr auto VARIADIC_USING = false; +constexpr auto VARIADIC_TEMPLATES = false; +constexpr auto LAMBDAS = false; +constexpr auto READ_VARINT = false; +constexpr auto CONCEPTS = true; + +bool isLucky(int n) +{ + return n == 13; +} + +// Forbid to be called with char or float (automatic conversion to 'int'). +bool isLucky(char) = delete; +bool isLucky(double) = delete; + +struct Pod +{ + int a; + double b; +}; + +int main() +{ + // Do not forget that 'endl' call 'flush' as well. Never use 'endl' when writing a lot of data (into a file for example). + cout << "Sandbox C++" << endl; + cout << "-----------" << endl; + + auto startTime = chrono::steady_clock::now(); + + if constexpr (DEFAULT_METHODS_ENABLED) + DefaultMethods::tests(); + + if constexpr (TRAITS_ENABLED) + Traits::tests(); + + if constexpr (POINTER_TO_MEMBER) + PointerToMember::tests(); + + if constexpr (FUNCTIONS_AS_TEMPLATE) + FunctionsAsTemplate::tests(); + + if constexpr (COST_OF_USING_STATIC) + CostOfUsingStatic::tests(); + + if constexpr (TEMPLATE_METAPROGRAMMING) + TemplateMetaProgramming::tests(); + + if constexpr (NEXT_AND_EXCHANGE) + NextAndExchange::tests(); + + if constexpr (BIND) + Bind::tests(); + + if constexpr (CONSTEXPR_IF) + ConstexprIf::tests(); + + if constexpr (FOLD_EXPRESSIONS) + FoldExpressions::tests(); + + if constexpr (IF_AND_SWITCH_INIT_STATEMENTS) + IfAndSwitchInitStatements::tests(); + + if constexpr (AGGREGATE_INITIALIZATIONS) + AggregateInitializations::tests(); + + if constexpr (VARIADIC_USING) + VariadicUsing::tests(); + + if constexpr (VARIADIC_TEMPLATES) + VariadicTemplates::tests(); + + if constexpr (LAMBDAS) + Lambdas::tests(); + + if constexpr (READ_VARINT) + ReadVarint::tests(); + + if constexpr (CONCEPTS) + Concepts::tests(); + + auto endTime = chrono::steady_clock::now(); + + cout << "-----------" << endl; + cout << "Elapsed time: " << chrono::duration_cast(endTime - startTime).count() << " ms" << endl; + + /* + cout << "Press ENTER to quit" << endl; + cin.ignore(); + */ +}