├── .gitmodules ├── .gitignore ├── meson.build ├── main.cpp ├── test └── type_name_pt.cpp ├── README.md ├── type_name_pt.hpp ├── type_name_rt.hpp └── LICENSE /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "subprojects/subarray"] 2 | path = subprojects/subarray 3 | url = https://github.com/willwray/subarray.git 4 | branch = preconcept 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('type_name', 'cpp', default_options : 'cpp_std=c++17') 2 | 3 | src = ['main.cpp'] 4 | 5 | subprojects = ['subarray'] 6 | 7 | foreach s : subprojects 8 | dep = s + '_dep' 9 | set_variable(dep, subproject(s).get_variable(dep)) 10 | endforeach 11 | 12 | executable('type_name', src, dependencies : [subarray_dep]) 13 | 14 | test('test type_name_pt', 15 | executable('type_name_pt', 'test/type_name_pt.cpp' 16 | , dependencies : [ subarray_dep] 17 | ) 18 | ) 19 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "type_name_rt.hpp" 3 | #include "type_name_pt.hpp" 4 | 5 | // std::array output operator, for type_name_pt output 6 | template 7 | std::ostream& operator<<(std::ostream& o, std::array const& a) 8 | { 9 | for (char c : a) o.put(c); 10 | return o; 11 | } 12 | 13 | constexpr char static_var{}; 14 | 15 | int main() 16 | { 17 | std::cout << "AUTO_NAME &static_var : " << auto_name_pt<&static_var> << '\n'; 18 | std::cout << "AUTO_NAME char{} : " << auto_name_pt << '\n'; 19 | 20 | std::cout << '\n'; 21 | 22 | std::cout << "TYPE_NAME char _PT : " << type_name_pt << '\n'; 23 | std::cout << " _RT : " << type_name_rt << '\n'; 24 | std::cout << "TYPE_NAME int& _PT : " << type_name_pt << '\n'; 25 | std::cout << " _RT : " << type_name_rt << '\n'; 26 | std::cout << "TYPE_NAME bool&& _PT : " << type_name_pt << '\n'; 27 | std::cout << " _RT : " << type_name_rt << '\n'; 28 | std::cout << "TYPE_NAME int const& _PT : " << type_name_pt << '\n'; 29 | std::cout << " _RT : " << type_name_rt << '\n'; 30 | 31 | std::cout << '\n'; 32 | 33 | const volatile char abc[1][2][3]{}; 34 | using ABC = decltype(abc); 35 | 36 | std::cout << "TYPE_NAME const volatile char[1][2][3] _PT: " << type_name_pt << '\n'; 37 | std::cout << " _RT: " << type_name_rt << '\n'; 38 | 39 | std::cout << '\n'; 40 | 41 | std::cout << "TYPE_NAME std::string : _PT " << type_name_pt << '\n'; 42 | std::cout << " : _RT " << type_name_str() << '\n'; 43 | } 44 | -------------------------------------------------------------------------------- /test/type_name_pt.cpp: -------------------------------------------------------------------------------- 1 | #include "type_name_pt.hpp" 2 | 3 | /* 4 | *** These tests are highly dependent on platform and version *** 5 | */ 6 | 7 | #if defined(__clang__) 8 | # define GN_CL_MS(gnu,clang,msvc) clang 9 | #elif defined(__GNUC__) || defined(__GNUG__) 10 | # define GN_CL_MS(gnu,clang,msvc) gnu 11 | #elif defined(_MSC_VER) 12 | # define GN_CL_MS(gnu,clang,msvc) msvc 13 | #endif 14 | 15 | // constexpr comparison of std::array and char[N+1] 16 | // *** SKIPS SPACES *** 17 | template 18 | constexpr bool operator==( std::array const& a, char const (&b)[B] ) 19 | { 20 | for (size_t ai=0, bi=0; ai!=A && (bi+1u)!=B; ++ai, ++bi) 21 | { 22 | while (a[ai]==' ') ++ai; 23 | while (b[bi]==' ') ++bi; 24 | if (a[ai] != b[bi]) return false; 25 | } 26 | return true; 27 | } 28 | 29 | // Non-type template arg tests 30 | 31 | // Different Integral types give same output (not good) 32 | static_assert( auto_name_pt<0> == "0"); 33 | static_assert( auto_name_pt<0U> == "0"); 34 | static_assert( auto_name_pt == "0"); 35 | static_assert( auto_name_pt == "0"); 36 | 37 | static_assert( auto_name_pt<1> == "1"); 38 | static_assert( auto_name_pt<1U> == "1"); 39 | static_assert( auto_name_pt == "1"); 40 | static_assert( auto_name_pt == "1"); 41 | 42 | // Except char c, output as 'c' for printable c, else escape sequence 43 | static_assert( auto_name_pt<'0'> == "'0'"); 44 | static_assert( auto_name_pt == 45 | GN_CL_MS (R"('\000')" 46 | , R"('\x00')" 47 | , R"('\x00')") ); 48 | 49 | enum e { a, b }; 50 | static_assert( auto_name_pt == GN_CL_MS("(e)0","a","a") ); 51 | static_assert( auto_name_pt == GN_CL_MS("(e)1","b","b") ); 52 | enum class E { m, n }; 53 | static_assert( auto_name_pt == GN_CL_MS("(E)0","E::m","E::m") ); 54 | static_assert( auto_name_pt == GN_CL_MS("(E)1","E::n","E::n") ); 55 | 56 | enum C : char { y, z }; 57 | static_assert( auto_name_pt == GN_CL_MS("(C)0","y","y") ); 58 | static_assert( auto_name_pt == GN_CL_MS("(C)1","z","z") ); 59 | 60 | struct ch { char c; }; 61 | static_assert( auto_name_pt<&ch::c> == "&ch::c"); 62 | constexpr ch c{}; 63 | static_assert( auto_name_pt<&c> == GN_CL_MS("(& c)", "&c", "&c") ); 64 | 65 | static_assert( type_name_pt == "char ch::*"); 66 | 67 | static_assert( type_name_pt == "int"); 68 | static_assert( type_name_pt == "int&"); 69 | static_assert( type_name_pt == "int*"); 70 | static_assert( type_name_pt == "int"); 71 | 72 | 73 | static_assert( type_name_pt == 74 | GN_CL_MS("std::__cxx11::basic_string" 75 | , "std::__cxx11::basic_string, std::allocator >" 76 | , "std::__cxx11::basic_string") ); 77 | 78 | int main() 79 | { 80 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # type_name 2 | 3 | ## C++ `type_name` utilities for pretty-printing type names. 4 | 5 | Originally inspired by [Howard Hinnant's type_name code](#HH), posted in reponse to: 6 | >"[How can I see the type deduced for a template type parameter?](http://stackoverflow.com/a/18369732)" 7 | StackOverflow, August 2013. 8 | 9 | The implementation is based on C++ typeinfo (RTTI, to become constexpr in C++20). 10 | 11 | ```c++ 12 | typeid(T).name() 13 | ``` 14 | 15 | On GCC, Clang and compilers using the [Itanium ABI](http://mentorembedded.github.io/cxx-abi/) the result is a mangled name. 16 | On these platforms the name is demangled using the `abi::__cxa_demangle()` function. 17 | 18 | ## C++17 `` 19 | 20 | 1. `type_name_str()` 21 | Returns a `std::string` copy of the demangled `typeid` name. 22 | On each call it does all the work, and cleans it all up 23 | (i.e. it frees any demangle allocation once copied from). 24 | 25 | 2. `type_name_rt` 26 | A `std::string_view` global constant (a view into the 27 | demangle buffer, on CXXABI, which is not ever free'd). 28 | All work is done in static initialization, before main() 29 | 30 | * Failure is signaled by an empty return value; `""` 31 | (indicates a demangle failure as typeid is assumed failsafe). 32 | 33 | ### Requirements 34 | 35 | C++17 for `string_view`, constexpr-if and `__has_include` 36 | RTTI, the compiler's runtime type information, must be enabled. 37 | 38 | ### Dependencies 39 | 40 | From `std`: 41 | >`` for `std::strlen` 42 | ``,`` as the return values. 43 | `` for `std::conditional`. 44 | `` (RTTI) for typeid(T).name(), an implementation-defined name. 45 | `` for `std::free`. 46 | `` for `std::unique_ptr` 47 | 48 | Platform dependency: 49 | >`` for demangling (on CXXABI platforms only - GCC, Clang, etc.) 50 | 51 | ### Usage example 52 | 53 | Because the type is supplied as a template parameter, `decltype(expr)` is required 54 | to query the type of an expression: 55 | 56 | ```C++ 57 | const volatile char abc[1][2][3]{}; 58 | std::cout << type_name_rt(); 59 | ``` 60 | 61 | ...produces output (different format is possible on different platforms): 62 | 63 | ``` 64 | char const volatile [1][2][3] 65 | ``` 66 | 67 | ## Design notes 68 | Firstly, note that the type argument has to be provided as a template parameter; type deduction from a regular function argument is not sufficient because deduction cannot distinguish all possible passed types. In other words, it is not possible to wrap `decltype()` or implement it otherwise. 69 | 70 | In principal, with the type known at compile time, a fully constexpr implementation of `type_name` should be possible, for example as a constexpr variable template whose value is some compile-time string type containing the human-readable type name. 71 | 72 | In practice, when based on the C++ `typeid()` operator, a fully constexpr implementation is not generally possible. 73 | 74 | 75 |

Howard Hinnant's C++11 type_name code

76 | 77 | ```C++ 78 | template 79 | std::string 80 | type_name() 81 | { 82 | using TR = typename std::remove_reference::type; 83 | std::unique_ptr own ( 84 | #ifndef _MSC_VER 85 | abi::__cxa_demangle (typeid(TR).name(), nullptr, 86 | nullptr, nullptr), 87 | #else 88 | nullptr, 89 | #endif 90 | std::free 91 | ); 92 | std::string r = own != nullptr ? own.get() : typeid(TR).name(); 93 | if (std::is_const::value) 94 | r += " const"; 95 | if (std::is_volatile::value) 96 | r += " volatile"; 97 | if (std::is_lvalue_reference::value) 98 | r += "&"; 99 | else if (std::is_rvalue_reference::value) 100 | r += "&&"; 101 | return r; 102 | } 103 | ``` 104 | -------------------------------------------------------------------------------- /type_name_pt.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018 Will Wray https://keybase.io/willwray 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #pragma once 8 | 9 | #include "subarray.hpp" 10 | 11 | /* 12 | "type_name_pt.hpp": get type names at 'preprocessor time' (hence 'pt') 13 | ^^^^^^^^^^^^^^^^ 14 | This header defines, in global scope, a pair of variable templates 15 | (constexpr): 16 | type_name_pt a std::array containing a name for type T. 17 | auto_name_pt a std::array containing a 'name' for value v 18 | (i.e. the non-type arg's value in a char-string form). 19 | (A future constexpr string type could replace std::array). 20 | The 'name' of the template arg is extracted from the output of 21 | (non-standard) 'pretty function' preprocessor directives: 22 | __FUNCSIG__ on MSVC 23 | __PRETTY_FUNCTION__ on GCC, Clang, etc. 24 | These are constexpr-usable static C-strings of unspecified format 25 | that can differ between compilers and between releases of a compiler. 26 | I.e. this method is not portable or forward/backward compatible*. 27 | The 'name' of an alias is the aliased type name, often quite verbose. 28 | For example, the main compilers give these results for std::string: 29 | type_name_pt 30 | on Clang: "std::__1::basic_string" 31 | on GCC: "std::__cxx11::basic_string" 32 | on MSVC: "class std::basic_string, 33 | class std::allocator >" 34 | A library could provide explicit specializations for std aliases, 35 | and users can specialize as needed, but the need to 'register' types 36 | renders this lib 'pretty pointless' - may as well register all types. 37 | See type_name_ct for compile-time type names via TMP & registration. 38 | * Boost type_index is a well-supported alternative with good backward 39 | compatibility and multi-platform testing. It is based on the same 40 | preprocessor directives so has similar compromises. 41 | */ 42 | 43 | namespace impl 44 | { 45 | // Implementation note: 46 | // There's no way to test at compile-time if __PRETTY_FUNCTION__ exists 47 | // so test #ifdef __FUNCSIG__ instead and #else __PRETTY_FUNCTION__. 48 | 49 | // PTTS; Preprocessor-Time Typename Size 50 | // 51 | template 52 | constexpr 53 | auto 54 | PTTS() // id must be 4-characters, the same length as 'PTTI' below 55 | { 56 | return sizeof 57 | ( 58 | # if defined(__FUNCSIG__) 59 | __FUNCSIG__ 60 | # else 61 | __PRETTY_FUNCTION__ 62 | # endif 63 | ); 64 | } 65 | 66 | // PTTI() Returns a std::array containing a type name for T 67 | // extracted from the preprocessor 'pretty function' output. 68 | // 69 | template 70 | constexpr 71 | auto 72 | PTTI() 73 | { 74 | // Changes to the output prefix are more common than suffix changes, 75 | // so assume the suffix format is fixed and search backwards. 76 | 77 | # if defined(__FUNCSIG__) 78 | // FUNCSIG example on recent MSVC: 79 | // 80 | // PTTI() ----> "auto __cdecl PTTI(void)" 81 | // ^^^^^^^^^^^^^^^^^^ ^^^^^^^ 82 | // prefix suffix 83 | 84 | // (type arg is arbitrary) 85 | constexpr long FS_T_prefix_size = PTTS() 86 | - sizeof( "int>(void)"); 87 | constexpr long FS_T_suffix_size = sizeof( ">(void)"); 88 | 89 | return ltl::subarray(__FUNCSIG__); 91 | # else 92 | 93 | // PRETTY_FUNCTION example on recent GCC: 94 | // 95 | // PTTI() ----> "constexpr auto PTTI() [with T = int]" 96 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ 97 | // prefix suffix 98 | 99 | constexpr long PF_T_prefix_size = PTTS() 100 | - sizeof( "int]"); 101 | constexpr long PF_T_suffix_size = sizeof( "]"); 102 | 103 | return ltl::subarray(__PRETTY_FUNCTION__); 105 | # endif 106 | } 107 | 108 | // PTvS; Preprocessor-Time value Size 109 | // 110 | template 111 | constexpr 112 | auto 113 | PTvS() // id must be 4-characters, the same length as 'PTvI' below 114 | { 115 | return sizeof 116 | ( 117 | # if defined(__FUNCSIG__) 118 | __FUNCSIG__ 119 | # else 120 | __PRETTY_FUNCTION__ 121 | # endif 122 | ); 123 | } 124 | 125 | // PTvI() Returns a std::array containing a printable string for v 126 | // extracted from the preprocessor 'pretty function' output. 127 | // 128 | template 129 | constexpr 130 | auto 131 | PTvI() 132 | { 133 | # if defined(__FUNCSIG__) 134 | constexpr long FS_v_prefix_size = PTvS<1>() 135 | - sizeof( "1>(void)"); 136 | constexpr long FS_v_suffix_size = sizeof( ">(void)"); 137 | 138 | return ltl::subarray(__FUNCSIG__); 140 | # else 141 | constexpr long PF_v_prefix_size = PTvS<1>() 142 | - sizeof( "1]"); 143 | constexpr long PF_v_suffix_size = sizeof( "]"); 144 | 145 | return ltl::subarray(__PRETTY_FUNCTION__); 147 | # endif 148 | } 149 | 150 | } // namespace impl 151 | 152 | template 153 | inline 154 | constexpr auto type_name_pt = impl::PTTI(); 155 | 156 | template 157 | inline 158 | constexpr auto auto_name_pt = impl::PTvI(); 159 | -------------------------------------------------------------------------------- /type_name_rt.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Will Wray https://keybase.io/willwray 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if __has_include() 15 | # include 16 | # include 17 | # include 18 | #endif 19 | 20 | constexpr bool CXXABI 21 | { 22 | #if __has_include() 23 | true 24 | #endif 25 | }; 26 | 27 | /* 28 | "type_name_rt.hpp": get type names at runtime (hence 'rt') 29 | ^^^^^^^^^^^^^^^^ 30 | This header defines, in global scope (i.e. not namespace'd): 31 | (1) A function template type_name_str() for extracting a type's name. 32 | (2) A variable template type_name_rt initialized to the type's name. 33 | (also an incomplete class template IdT, an implementation detail.) 34 | The template type parameter T is mapped to a readable name for the type. 35 | The work is done at runtime by what is the most standard current method; 36 | runtime type information (RTTI) and, on CXXABI, a demangle call 37 | (for compile-time alternatives see type_name_pt or type_name_ct). 38 | (1) type_name_str() 39 | Returns a std::string copy of the demangled typeid name. 40 | On each call it does all the work, and cleans it all up 41 | (i.e. it frees any demangle allocation once copied from). 42 | 43 | (2) type_name_rt 44 | A std::string_view global constant (a view into the 45 | demangle buffer, on CXXABI, which is not ever free'd). 46 | All work is done in static initialization, before main() 47 | 48 | Failure is signalled by an empty return value; "" 49 | (indicates a demangle failure as typeid is assumed fail-safe). 50 | Requirements: 51 | C++17 for string_view, constexpr-if, CTAD (unique_ptr) and __has_include 52 | RTTI, the compiler's runtime type information, must be enabled 53 | Dependencies: ,, for std::conditional 54 | (RTTI) 55 | for typeid(T).name(), an implementation-defined name. 56 | (on CXXABI platforms only - GCC, Clang, etc.) 57 | for abi::__cxa_demangle(name,...) 58 | to map typeid(T).name to a human readable name for T. 59 | for std::free, for std::unique_ptr 60 | E.g. 61 | int i; 62 | std::cout << type_name_rt << "\n^^^ tada!"; 63 | --- stdout --- 64 | int 65 | ^^^ tada! 66 | */ 67 | 68 | // IdT wraps T as template param so typeid can't decay ref or cv quals. 69 | // An implementation detail; must be a 3-character id, any 3 chars will do. 70 | template struct IdT {}; 71 | 72 | namespace impl 73 | { 74 | // demangle( const char* name) 75 | // 76 | // (1) On non-CXXABI returns name, regardless of the template parameter. 77 | // i.e. the function does nothing but return its parameter, a char*. 78 | // 79 | // (2) On CXXABI the demangle ABI is called and the result is returned 80 | // with return type depending on the boolean template argument: 81 | // (a) char* by default (Free=false). Any demangle malloc is not free'd. 82 | // (b) unique_ptr (Free=true) to RAII-free any malloc'd chars. 83 | // 84 | // The input name should be a valid mangled name like typeid(T).name() 85 | // Null return value implies demangle fail (no malloc, free is harmless). 86 | // 87 | template 88 | auto 89 | demangle(char const* name) noexcept(!CXXABI) 90 | { 91 | if constexpr (!CXXABI) { 92 | return name; // NOP: assume already demangled if not on CXXABI 93 | } else { 94 | auto dmg = abi::__cxa_demangle(name, nullptr, nullptr, nullptr); 95 | if constexpr (Free) 96 | return std::unique_ptr( dmg, std::free); 97 | else 98 | return dmg; 99 | } 100 | } 101 | 102 | // prefix_len (constant): prefix length of demangled typeid(IdT) 103 | // for different compilers (remove 4 chars "int>" from the length) 104 | size_t IdT_prefix_len() 105 | { 106 | static size_t const len = std::strlen(demangle<>(typeid(IdT).name())) 107 | - std::strlen("int>"); 108 | return len; 109 | } 110 | 111 | template 112 | using remove_cvref_t = std::remove_cv_t>; 113 | 114 | template 115 | inline constexpr bool is_cvref_v = !std::is_same_v>; 116 | 117 | // type_name_rt() Returns string, frees any malloc from ABI demangle 118 | // type_name_rt() Returns string_view, does not free demangle malloc 119 | // 120 | template 121 | auto 122 | type_name_rt() noexcept(!CXXABI) -> std::conditional_t 124 | { 125 | if constexpr (!is_cvref_v) 126 | { 127 | if (auto dmg = demangle(typeid(T).name())) 128 | { 129 | return { &*dmg }; 130 | } 131 | } 132 | else // wrap all cvref types for now - maybe only do functions and arrays 133 | { 134 | if (auto dmg = demangle(typeid(IdT).name())) 135 | { 136 | size_t const p = IdT_prefix_len(); 137 | return { &*dmg + p, std::strlen(&*dmg) - p - 1 }; 138 | } 139 | } 140 | return ""; 141 | } 142 | } // namespace impl 143 | 144 | // type_name_str() Returns a std::string copy of the demangled typeid name. 145 | // 146 | template 147 | std::string 148 | const type_name_str() { return impl::type_name_rt(); } 149 | 150 | // type_name_rt Global constant; "The Demangle that Never Dangles" 151 | // 152 | template 153 | inline 154 | std::string_view 155 | const type_name_rt = impl::type_name_rt(); 156 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | --------------------------------------------------------------------------------