diff --git a/.clang-format b/.clang-format index 7e099f92..71fc3343 100644 --- a/.clang-format +++ b/.clang-format @@ -23,7 +23,7 @@ AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: true -BraceWrapping: +BraceWrapping: AfterCaseLabel: false AfterClass: false AfterControlStatement: false @@ -60,12 +60,12 @@ DerivePointerAlignment: true DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true -ForEachMacros: +ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Regroup -IncludeCategories: +IncludeCategories: - Regex: '^' Priority: 2 - Regex: '^<.*\.h>' @@ -99,9 +99,9 @@ PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left -RawStringFormats: +RawStringFormats: - Language: Cpp - Delimiters: + Delimiters: - cc - CC - cpp @@ -112,12 +112,12 @@ RawStringFormats: CanonicalDelimiter: '' BasedOnStyle: google - Language: TextProto - Delimiters: + Delimiters: - pb - PB - proto - PROTO - EnclosingFunctions: + EnclosingFunctions: - EqualsProto - EquivToProto - PARSE_PARTIAL_TEXT_PROTO @@ -147,10 +147,9 @@ SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto -StatementMacros: +StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION TabWidth: 8 UseTab: Never ... - diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..c12f566b --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,17 @@ +# Dockerfile for Ubuntu 22.04 with C++ development tools. + +# Set the base image. +FROM ubuntu:22.04 + +# Install gcc, clang and some supporting tools for downloading/installing later tools. +RUN apt-get update && apt-get install -y wget g++ lcov llvm git gpg ninja-build software-properties-common unzip + +# Install newer CMake from kitware. +RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null \ +&& apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ jammy main' && apt-get update && apt-get install -y cmake + +# Install bazel. +RUN wget https://github.com/bazelbuild/bazel/releases/download/6.4.0/bazel-6.4.0-installer-linux-x86_64.sh \ +&& bash bazel-6.4.0-installer-linux-x86_64.sh && rm bazel-6.4.0-installer-linux-x86_64.sh + +ENV PATH="/usr/local/bin:$PATH" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..e49fc9a9 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,6 @@ +{ + "name": "C++", + "build": { + "dockerfile": "Dockerfile" + }, +} diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index d50d911d..bf69a7b9 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -14,23 +14,23 @@ jobs: matrix: settings: - { - name: "debug", + name: "Bazel test: debug", flags: "-c dbg", } - { - name: "optimized", + name: "Bazel test: optimized", flags: "-c opt", } - { - name: "address sanitizer", + name: "Bazel test: address sanitizer", flags: "--config=asan", } - { - name: "undefined behaviour sanitizer", + name: "Bazel test: undefined behaviour sanitizer", flags: "--config=ubsan", } - { - name: "thread sanitizer", + name: "Bazel test: thread sanitizer", flags: "--config=tsan", } steps: diff --git a/.github/workflows/integrity_checks.yml b/.github/workflows/integrity_checks.yml new file mode 100644 index 00000000..f2dfd48c --- /dev/null +++ b/.github/workflows/integrity_checks.yml @@ -0,0 +1,31 @@ +name: Integrity Checks + +on: + push: + branches: [main] + pull_request: + branches: [main] + +defaults: + run: + shell: bash + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + + - name: Install action-validator with asdf + uses: asdf-vm/actions/install@v2 + with: + tool_versions: | + action-validator 0.5.1 + + - name: Lint Actions + run: | + find .github/workflows -type f \( -iname \*.yaml -o -iname \*.yml \) \ + | xargs -I {} action-validator --verbose {} diff --git a/.gitignore b/.gitignore index a423f857..68e1846d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/ +.venv/ .vs/ .vscode/ _build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..0c794008 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +# .pre-commit-config.yaml +# ======================== +# +# pre-commit clean +# pre-commit install +# pre-commit install-hooks +# +# precommit hooks installation +# +# - pre-commit autoupdate +# +# - pre-commit run black +# +# continuous integration +# ====================== +# +# - pre-commit run --all-files +# +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: forbid-submodules + - id: requirements-txt-fixer + - id: trailing-whitespace diff --git a/CMakeLists.txt b/CMakeLists.txt index eb812ac1..f1d5c603 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,8 +85,8 @@ target_compile_features(polymorphic_inline_vtable INTERFACE cxx_std_23 ) -target_compile_definitions(polymorphic_inline_vtable - INTERFACE +target_compile_definitions(polymorphic_inline_vtable + INTERFACE XYZ_POLYMORPHIC_USES_EXPERIMENTAL_INLINE_VTABLE ) @@ -104,8 +104,8 @@ target_compile_features(polymorphic_sbo INTERFACE cxx_std_23 ) -target_compile_definitions(polymorphic_sbo - INTERFACE +target_compile_definitions(polymorphic_sbo + INTERFACE XYZ_POLYMORPHIC_USES_EXPERIMENTAL_SMALL_BUFFER_OPTIMIZATION ) @@ -143,7 +143,7 @@ if (${CPP_VALUE_TYPES_IS_NOT_SUBPROJECT}) CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO ) - + add_executable(indirect_test "") target_sources(indirect_test PRIVATE @@ -187,7 +187,7 @@ if (${CPP_VALUE_TYPES_IS_NOT_SUBPROJECT}) ) target_compile_options(polymorphic_sbo_test PRIVATE - $<$:-ftemplate-backtrace-limit=0> + $<$:-ftemplate-backtrace-limit=0> ) target_link_libraries(polymorphic_sbo_test PRIVATE diff --git a/CODEOWNERS b/CODEOWNERS index e9dbde94..34175c1d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -2,8 +2,8 @@ @jbcoe @twon -# CMake +# CMake CMakeLists.txt @twon -# Bazel +# Bazel *.bazel @jbcoe diff --git a/DRAFT.md b/DRAFT.md index e3bfc437..987878f0 100644 --- a/DRAFT.md +++ b/DRAFT.md @@ -128,7 +128,7 @@ struct A { class Composite { indirect a_; - + Constness foo() { return a_.foo(); } Constness foo() const { return a_.foo(); }; }; @@ -268,7 +268,7 @@ The template parameter `T` of `indirect` may be an incomplete type. template > class indirect { T* p_; // exposition only - Allocator allocator_; // exposition only + Allocator allocator_; // exposition only public: using value_type = T; using allocator_type = Allocator; @@ -288,7 +288,7 @@ class indirect { std::allocator_arg_t, const Allocator& alloc, const indirect& other); constexpr indirect(indirect&& other) noexcept; - + constexpr indirect( std::allocator_arg_t, const Allocator& alloc, indirect&& other) noexcept; @@ -665,7 +665,7 @@ constexpr auto operator<=>(const U& lhs, const indirect& rhs); * _Preconditions_: Alloc meets the _Cpp17Allocator_ requirements. #### X.Y.10 Hash support [indirect.hash] - + ```c++ template struct std::hash>; @@ -756,7 +756,7 @@ The template parameter `T` of `polymorphic` may be an incomplete type. template > class polymorphic { control_block* control_block_; // exposition only - Allocator allocator_; // exposition only + Allocator allocator_; // exposition only public: using value_type = T; using allocator_type = Allocator; @@ -771,12 +771,12 @@ class polymorphic { std::allocator_arg_t, const Allocator& alloc, std::in_place_type_t, Ts&&... ts); constexpr polymorphic(const polymorphic& other); - + constexpr polymorphic( std::allocator_arg_t, const Allocator& alloc, const polymorphic& other); constexpr polymorphic(polymorphic&& other) noexcept; - + constexpr polymorphic( std::allocator_arg_t, const Allocator& alloc, polymorphic&& other) noexcept; @@ -972,7 +972,7 @@ constexpr allocator_type get_allocator() const noexcept; * _Returns_: A copy of the Allocator object used to construct the owned object or, if that allocator has been replaced, a copy of the most recent replacement. - + #### X.Z.7 Swap [polymorphic.swap] ```c++ @@ -1029,11 +1029,7 @@ Otherwise, the interface of the specialization is as defined in [optional]. Add a new feature-test macro: ```c++ -<<<<<<< HEAD -#define __cpp_lib_polymorphic 2023XXL -======= -#define __cpp_lib_value_types 2023XXL ->>>>>>> 5ccaf0258047213454eaec39d2a1fcc9cfe83dd6 +#define __cpp_lib_value_types 2023XXL ``` ## Reference implementation @@ -1245,7 +1241,7 @@ class Class { Class& operator=(const Class&); Class(Class&&) noexcept; Class& operator=(Class&&) noexcept; - + void do_something(); }; ``` @@ -1295,7 +1291,7 @@ class Class { Class& operator=(const Class&); Class(Class&&) noexcept; Class& operator=(Class&&) noexcept; - + void do_something(); }; ``` @@ -1372,7 +1368,7 @@ class Picture { ``` #### After, using `polymorphic` - + ```c++ class Canvas; diff --git a/README.md b/README.md index f6b45dc4..88794807 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ class Composite { xyz::indirect a_; // a_ owns an object of type A xyz::indirect b_; // b_ owns an object of type B public: - Composite(const A& a, const B& b) : - a_(std::in_place, a), + Composite(const A& a, const B& b) : + a_(std::in_place, a), b_(std::in_place, b) {} // ... @@ -69,8 +69,8 @@ class CompositeWithPolymorphicMembers { xyz::polymorphic y_; // y_ owns an object of type Y or derived from Y public: template - Composite(const Tx& x, const Ty& y) : - a_(std::in_place_type, x), + Composite(const Tx& x, const Ty& y) : + a_(std::in_place_type, x), b_(std::in_place_type, y) {} // ... @@ -94,12 +94,16 @@ This code is licensed under the MIT License. See [LICENSE](LICENSE) for details. ## Talks and presentations We spoke about an earlier draft at [C++ on -Sea](https://www.youtube.com/watch?v=sjLRX4WMvlU) in 2022. +Sea](https://www.youtube.com/watch?v=sjLRX4WMvlU) in 2022. -There are some significant design changes since this talk was given (after feedback -and discussion at a C++ London meetup). We've pared down the number of constructors +There are some significant design changes since this talk was given (after feedback +and discussion at a C++ London meetup). We've pared down the number of constructors and made the null state unobservable. +## Developer Guide + +For building and working with the project, please see the [developer guide](docs/developer-guide.md). + ## References * [TK's allocator user guide] diff --git a/docs/developer-guide.md b/docs/developer-guide.md new file mode 100644 index 00000000..8e03cb99 --- /dev/null +++ b/docs/developer-guide.md @@ -0,0 +1,44 @@ +# Using pre-commit for git hooks + +This repository uses the Python `pre-commit` library to manage git hook run as +part of the commit process. Use the following steps to install a virtual +environment with pre-commmit set up, and then use precommit to install git hooks +it to your local repository. + +```bash +cd +python3 -m venv .venv # Create a Python virtual env +source ./.venv/bin/activate # Activate the virtual env for bash by source. +pip install -r requirements.txt # Install latest requirements including pre-commit +pre-commit install # Use pre-commit to install git hooks into the working repository. +``` + +# Building with CMake + +To build the repository with CMake use the following steps +```bash +cd +mkdir build # Make a build directory +cd build # Switch into the build directory +cmake ../ # Generate build system specified in root with cmake +cmake --build ./ # Build the underlying build system via CMake +``` + +# Including in your own project + +To use the value types code in your own CMake project then you can pull +the project in as a dependency via CMake's FetchContent module as follows: + +``` +FetchContent_Declare( + value_types + GIT_REPOSITORY https://github.com/jbcoe/value_types +) +FetchContent_MakeAvailable(value_types) + +add_executable(my_program) +target_link_libraries(my_program + PUBLIC + value_types::value_types +) +``` diff --git a/presentations/value_types_2023_10_27.md b/presentations/value_types_2023_10_27.md index 4836d16c..eaf9a9b2 100644 --- a/presentations/value_types_2023_10_27.md +++ b/presentations/value_types_2023_10_27.md @@ -37,7 +37,7 @@ class Circle { std::string colour_; public: - std::string_view colour() const; + std::string_view colour() const; double area() const; }; ``` @@ -69,10 +69,10 @@ We can define special member functions to create, copy, move or destroy instance ```cpp class Circle { Circle(std::string_view colour, double radius, Point position); - + Circle(const Circle&); Circle& operator=(const Circle&); - + Circle(Circle&&); Circle& operator=(Circle&&); @@ -88,8 +88,8 @@ class Circle { * The compiler will (sometimes) generate special member functions for us. -* Generated special member functions are member-by-member calls to the appropriate - special member function of each member object. +* Generated special member functions are member-by-member calls to the appropriate + special member function of each member object. --- @@ -121,7 +121,7 @@ Member functions in C++ can be const-qualified: ```cpp struct A { void foo() const; - void foo(); + void foo(); void bar(); }; ``` @@ -268,7 +268,7 @@ We might require a member of our composite class to be one of a number of types. Our class will need to reserve storage for our polymorphic data member. ---- +--- # Closed-set polymorphism @@ -285,7 +285,7 @@ class Taco { Storing a closed-set polymorphic member directly is possible as `variant` and `optional` reserve enough memory for the largest possible type. ---- +--- # Open-set polymorphism @@ -324,7 +324,7 @@ class A { or the base type in a class heirarchy: ``` -struct Shape { +struct Shape { virtual void Draw() const = 0; }; @@ -423,7 +423,7 @@ class A { }; ``` -With `shared_ptr` members, the compiler can generate all special member functions for us. +With `shared_ptr` members, the compiler can generate all special member functions for us. Sadly this is not much of an improvement as the copy constructor and assignment operator will not copy the `B` object that we point to, only add references to it. @@ -439,7 +439,7 @@ class A { }; ``` -Again, the compiler can generate all special member functions for us. +Again, the compiler can generate all special member functions for us. Copy and assignement will add references to the same `B` object but seeing as it's immutable that could be ok (so long as it's not mutable by another route). @@ -541,14 +541,14 @@ class polymorphic { [[no_unique_address]] A alloc_; public: - // Constructors and assignment. + // Constructors and assignment. constexpr T* operator->() noexcept { return *cb_->p_; } constexpr const T* operator->() const noexcept { return *cb_->p_; } constexpr T& operator*() noexcept { return **cb_->p_; } - constexpr const T& operator*() const noexcept { return **cb_->p_; } - + constexpr const T& operator*() const noexcept { return **cb_->p_; } + constexpr bool valueless_after_move() const noexcept { return bool(cb_); } }; ``` @@ -728,9 +728,9 @@ jbcoe/value_types is licensed under the MIT License -A short and simple permissive license with conditions only +A short and simple permissive license with conditions only requiring preservation of copyright and license notices. -Licensed works, modifications, and larger works may be +Licensed works, modifications, and larger works may be distributed under different terms and without source code. ``` @@ -800,7 +800,7 @@ constexpr T& operator*() noexcept; constexpr T* operator->() noexcept; constexpr const T& operator*() const noexcept; -constexpr const T* operator->() const noexcept; +constexpr const T* operator->() const noexcept; ``` --- @@ -825,7 +825,7 @@ class indirect { T* ptr_; [[no_unique_address]] Allocator a_; public: - // Constructors elided + // Constructors elided constexpr T* operator->() noexcept { return ptr_; } constexpr const T* operator->() const noexcept { return ptr_; } @@ -847,9 +847,9 @@ jbcoe/value_types is licensed under the MIT License -A short and simple permissive license with conditions only +A short and simple permissive license with conditions only requiring preservation of copyright and license notices. -Licensed works, modifications, and larger works may be +Licensed works, modifications, and larger works may be distributed under different terms and without source code. ``` --- @@ -883,4 +883,4 @@ I have travel booked to present this work to the standards committee in November Many thanks to Sean Parent and to the Library Evolution Working group from the C++ Standards committee for interesting early discussion in the design of `polymorphic`. -Thanks to our GitHub contributors who've made worked with us to improve our reference implementations. \ No newline at end of file +Thanks to our GitHub contributors who've made worked with us to improve our reference implementations. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..416634f5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pre-commit