From 3a2a995f4a4f9791da9c487f31ef82a2feb5d8fa Mon Sep 17 00:00:00 2001 From: Stefanus Du Toit Date: Sun, 14 Sep 2014 21:00:50 -0400 Subject: [PATCH] Add code for C++11 in the Wild. --- .../README.md | 4 + .../auto-test.cc | 22 +++ .../auto.h | 22 +++ .../function.h | 22 +++ .../iterable.h | 17 +++ .../profile-spaceship.py | 35 +++++ .../spaceship.cc | 133 ++++++++++++++++++ 7 files changed, 255 insertions(+) create mode 100644 Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/README.md create mode 100644 Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto-test.cc create mode 100644 Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto.h create mode 100644 Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/function.h create mode 100644 Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/iterable.h create mode 100644 Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/profile-spaceship.py create mode 100644 Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/spaceship.cc diff --git a/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/README.md b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/README.md new file mode 100644 index 0000000..43819ff --- /dev/null +++ b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/README.md @@ -0,0 +1,4 @@ +# C++11 in the Wild - Techniques from a Real Codebase + +The C++ code in this directory is placed in the public domain and may +be reused or modified for any purpose, commercial or non-commercial. diff --git a/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto-test.cc b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto-test.cc new file mode 100644 index 0000000..74f1df6 --- /dev/null +++ b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto-test.cc @@ -0,0 +1,22 @@ +#ifdef __clang__ +#include +#else +// GCC 4.8 doesn't know that puts() is nothrow; we must give it a hint. +extern void puts(const char*) noexcept(true); +#endif + +#include "auto.h" + +extern void foo(); + +int main() { + if (true) { + Auto(puts("two")); + puts("one"); // compiler knows this doesn't throw + } + if (true) { + Auto(puts("three")); + foo(); // might throw an exception + } +} + diff --git a/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto.h b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto.h new file mode 100644 index 0000000..8b90039 --- /dev/null +++ b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/auto.h @@ -0,0 +1,22 @@ +#pragma once + +template class AtScopeExit { + Lambda& m_lambda; +public: + AtScopeExit(Lambda& action) : m_lambda(action) {} + ~AtScopeExit() { m_lambda(); } +}; + +#define TOKEN_PASTEx(x, y) x ## y +#define TOKEN_PASTE(x, y) TOKEN_PASTEx(x, y) + +#define Auto_INTERNAL1(lname, aname, ...) \ + auto lname = [&]() { __VA_ARGS__; }; \ + AtScopeExit aname(lname); + +#define Auto_INTERNAL2(ctr, ...) \ + Auto_INTERNAL1(TOKEN_PASTE(Auto_func_, ctr), \ + TOKEN_PASTE(Auto_instance_, ctr), __VA_ARGS__) + +#define Auto(...) Auto_INTERNAL2(__COUNTER__, __VA_ARGS__) + diff --git a/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/function.h b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/function.h new file mode 100644 index 0000000..880ab54 --- /dev/null +++ b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/function.h @@ -0,0 +1,22 @@ +#pragma once +#include + +struct ContainerBase { + virtual void perform() = 0; + virtual ~ContainerBase() = default; +}; + +template struct Container : ContainerBase { + Lambda m_lambda; + Container(Lambda&& lambda) : m_lambda(std::move(lambda)) {} + virtual void perform() { m_lambda(); } +}; + +class function { // equivalent to std::function + ContainerBase *m_ctr; +public: + template function(Lambda lambda) + : m_ctr(new Container(std::move(lambda))) {} + void operator()() { m_ctr->perform(); } + ~function() { delete m_ctr; } +}; diff --git a/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/iterable.h b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/iterable.h new file mode 100644 index 0000000..d3725e9 --- /dev/null +++ b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/iterable.h @@ -0,0 +1,17 @@ +template +class iterable +{ + It m_first, m_last; +public: + iterable() = default; + iterable(It first, It last) : + m_first(first), m_last(last) {} + It begin() const { return m_first; } + It end() const { return m_last; } +}; + +template +static inline iterable make_iterable(It a, It b) +{ + return iterable(a, b); +} diff --git a/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/profile-spaceship.py b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/profile-spaceship.py new file mode 100644 index 0000000..26a15dc --- /dev/null +++ b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/profile-spaceship.py @@ -0,0 +1,35 @@ +import os,time,sys + +spaceships = ['spaceship1', 'spaceship2'] +makes = ['make1', 'make2', 'make3'] + +cmd = 'clang++ -w -std=c++1y -stdlib=libc++ test.cc -o a.out -ftemplate-depth=2000 ' + ' '.join(sys.argv[1:]) + +def profile(cmd): + start = time.time() + os.system(cmd) + os.system(cmd) + os.system(cmd) + end = time.time() + return (end - start) / 3 + +print ' ', +for make in makes: + for spaceship in spaceships: + print '%12s' % make, +print '' +print ' ', +for make in makes: + for spaceship in spaceships: + print '%12s' % spaceship, +print '' + +for parameter in [1,2,4,8,16,32,64,128,256,512,1024]: + + # Profile each combination of SPACESHIP and MAKE, for parameter value "i". + print '%4d:' % parameter, + for make in makes: + for spaceship in spaceships: + t = profile('%s -DSPACESHIP=%s -DMAKE=%s -DPARAMETER=%d' % (cmd, spaceship, make, parameter)) + print '%12.4f' % t, + print '' diff --git a/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/spaceship.cc b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/spaceship.cc new file mode 100644 index 0000000..6055868 --- /dev/null +++ b/Presentations/C++11 in the Wild - Techniques from a Real Codebase - Arthur O'Dwyer - CppCon 2014/spaceship.cc @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include + +#ifndef MAKE + #error "-DMAKE= make1, make2, or make3" +#endif +#ifndef PARAMETER + #error "-DPARAMETER= 1,2,4,8,16,32,64,128,256, or 512" +#endif +#ifndef SPACESHIP + #error "-DSPACESHIP= spaceship1 or spaceship2" +#endif + +#if 1 +#define INDEX_SEQUENCE(NN) std::index_sequence +#define MAKE_INDEX_SEQUENCE(N) std::make_index_sequence +#else +#define INDEX_SEQUENCE(NN) std::__tuple_indices +#define MAKE_INDEX_SEQUENCE(N) typename std::__make_tuple_indices::type +#endif + +// The easy part. +// + +namespace std { + + template + constexpr int spaceship(const _Tp& __x, const _Up& __y) + { + return (__x < __y) ? -1 : (__y < __x) ? 1 : 0; + } + + template + int spaceship(const basic_string<_Cp,_Tp,_Ap>& __x, + const basic_string<_Cp,_Up,_Bp>& __y) + { + int __r = __x.compare(0, __x.size(), __y.data(), __y.size()); + return (__r < 0) ? -1 : (__r > 0); + } + +template struct __tuple_spaceship1 +{ + template + constexpr int operator()(const _Tp& __x, const _Up& __y) const + { + int __r = __tuple_spaceship1<_Ip-1>()(__x, __y); + return (__r != 0) ? __r : spaceship(get<_Ip-1>(__x), get<_Ip-1>(__y)); + } +}; + +template<> struct __tuple_spaceship1<0> +{ + template + constexpr int operator()(const _Tp&, const _Up&) const + { + return 0; + } +}; + +template +constexpr int spaceship1(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) +{ + static_assert(sizeof...(_Tp) == sizeof...(_Up), ""); + return __tuple_spaceship1()(__x, __y); +} + +template +constexpr int __tuple_spaceship2(const _Tp& __x, const _Up& __y, const INDEX_SEQUENCE(_Ip...)&) +{ + int __r = 0; + std::initializer_list x = { + (__r != 0) ? 0 : (__r = spaceship(get<_Ip>(__x), get<_Ip>(__y))) ... + }; + return __r; +} + +template +constexpr int spaceship2(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) +{ + static_assert(sizeof...(_Tp) == sizeof...(_Up), ""); + return __tuple_spaceship2(__x, __y, MAKE_INDEX_SEQUENCE(sizeof...(_Tp)){}); +} + +} // namespace std + + +namespace Foo { + class Widget { + int value; + public: + Widget(int v): value(v) {} + friend int spaceship(const Widget& w1, const Widget& w2) { return std::spaceship(w1.value, w2.value); } + void operator< (const Widget&) const { printf("BAAAD\n"); assert(false); } + void operator== (const Widget&) const { printf("BAAAD\n"); assert(false); } + void operator> (const Widget&) const { printf("BAAAD\n"); assert(false); } + }; +} + + +template auto make1() { return std::tuple_cat(make1(), make1()); } +template<> auto make1<1>() { return std::tuple("hello"); } +template<> auto make1<0>() { return std::tuple<>(); } +#define make1(N) make1() + +template auto make2(const INDEX_SEQUENCE(N...)&) { return std::tuple((N,"hello")...); } +template auto make2() { return make2(MAKE_INDEX_SEQUENCE(N){}); } +#define make2(N) make2() + +#define S1(X) X +#define S2(X) X,X +#define S4(X) X,X,X,X +#define S8(X) S4(X),S4(X) +#define S16(X) S8(X),S8(X) +#define S32(X) S16(X),S16(X) +#define S64(X) S32(X),S32(X) +#define S128(X) S64(X),S64(X) +#define S256(X) S128(X),S128(X) +#define S512(X) S256(X),S256(X) +#define TOKEN_PASTE(x,y) x##y +#define S(N,X) TOKEN_PASTE(S,N)(X) +#define make3(N) std::tuple{S(N,"hello")} + +int main() +{ + auto a = MAKE(PARAMETER); + + return std::SPACESHIP(a,a); +}