Skip to content

Commit

Permalink
Simplify and improve construction (#44)
Browse files Browse the repository at this point in the history
### Why 
Currently move and forward constructors are missing opportunities.

### What was changed
- Remove most of the constructors and just keep a forwarding
constructor.
- Remove the can_forward_construct skill, since it is now always
enabled.
- Some static functions in benchmarks were moved into an anonymous
namespace
- Fixed a number of missing headers
- Moved can_stream and can_hash into their own files
- can_stream is now both for input and output streams. Use can_ostream
and can_istream to only get one of their behaviors.

---------

Co-authored-by: Mikael Lindemann <[email protected]>
Co-authored-by: mikaellindemann <[email protected]>
  • Loading branch information
3 people authored Jun 22, 2024
1 parent ffeff8b commit d9f6fec
Show file tree
Hide file tree
Showing 30 changed files with 309 additions and 240 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
workflow_dispatch:

env:
VCPKG_COMMIT: "c8696863d371ab7f46e213d8f5ca923c4aef2a00"
VCPKG_COMMIT: "943c5ef1c8f6b5e6ced092b242c8299caae2ff01"

jobs:
version_bump:
Expand Down Expand Up @@ -227,7 +227,7 @@ jobs:
uses: KyleMayes/install-llvm-action@v1
with:
version: "17.0"

- name: Fix clang installations
if: matrix.os == 'ubuntu-22.04'
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ on:
schedule:
- cron: "44 8 * * 1"
env:
VCPKG_COMMIT: "c8696863d371ab7f46e213d8f5ca923c4aef2a00"
VCPKG_COMMIT: "943c5ef1c8f6b5e6ced092b242c8299caae2ff01"

jobs:
analyze:
Expand Down
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"clangd.path": "clangd-17",
"clangd.arguments": [
"-compile-commands-dir=${workspaceFolder}/build/dev"
],
"clang-format.executable": "clang-format-17",
"cpplint.filters": [
"-build/c++11",
Expand Down Expand Up @@ -114,4 +117,4 @@
"connectionId": "twig-energy",
"projectKey": "twig-energy_stronk"
}
}
}
2 changes: 1 addition & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"name": "clang-tidy",
"hidden": true,
"cacheVariables": {
"CMAKE_CXX_CLANG_TIDY": "clang-tidy-17;--header-filter=${sourceDir}/*"
"CMAKE_CXX_CLANG_TIDY": "clang-tidy-17;--header-filter=^${sourceDir}/(include|tests|benchmarks)"
}
},
{
Expand Down
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
#include <iostream>
#include <string>

#include <stronk/can_stream.h>
#include <stronk/stronk.h>

struct FirstName : twig::stronk<FirstName, std::string, twig::can_stream>
struct FirstName : twig::stronk<FirstName, std::string, twig::can_ostream>
{
using stronk::stronk;
};
Expand All @@ -42,7 +43,7 @@ struct LastName : twig::stronk<LastName, std::string>
// Strong types protects you from accidentally passing the wrong argument to the wrong parameter.
void print_name(const LastName& lastname, const FirstName& firstname)
{
// The twig::can_stream skill overloads the `operator<<(ostream&)` for your type.
// The twig::can_ostream skill overloads the `operator<<(ostream&)` for your type.
std::cout << firstname << " ";
// You can also access the underlying type by using the .unwrap<Type>() function.
std::cout << lastname.unwrap<LastName>() << std::endl;
Expand All @@ -56,10 +57,12 @@ auto main() -> int
On top of providing strong type utilities, `stronk` also enables unit-like behavior:
```cpp :file=./examples/unit_energy_example.cpp:line_start=0:line_end=23
```cpp :file=./examples/unit_energy_example.cpp:line_start=0:line_end=25
#include <ratio>
#include <type_traits>
#include <stronk/prefabs.h>
#include <stronk/stronk.h>
#include <stronk/unit.h>
// We introduce a unit type with a default set of skills with the `stronk_default_unit` prefab
Expand All @@ -84,7 +87,7 @@ void watts_and_identity_units()

Different units can be combined by multiplying or dividing them:

```cpp :file=./examples/unit_energy_example.cpp:line_start=24:line_end=45
```cpp :file=./examples/unit_energy_example.cpp:line_start=26:line_end=47
// Lets introduce hours as a new unit_like type
struct Hours : twig::stronk<Hours, double, twig::unit>
{
Expand All @@ -110,7 +113,7 @@ void watt_hours_and_generating_new_units()

These new generated types are also units which can be used to generate new units:

```cpp :file=./examples/unit_energy_example.cpp:line_start=46:line_end=65
```cpp :file=./examples/unit_energy_example.cpp:line_start=48:line_end=67
// Lets introduce a type for euros, and start combining more types.
struct Euro : twig::stronk<Euro, double, twig::unit>
{
Expand Down Expand Up @@ -147,7 +150,7 @@ Skills adds functionality to your stronk types. We have implemented a number of
- `can_divide`: binary `operator/` and `operator=/` (not compatible with units, we encourage you to use units instead)
- `can_abs`: overloads `twig::abs`
- `can_isnan`: overloads `twig::isnan`
- `can_stream`: overloads `operator<<(std::ostream)`, stream the underlying value to the stream.
- `can_stream`: overloads `operator<<(std::ostream)` and `operator<<(std::istream)`, stream the underlying value to the stream, or create from stream. For only `ostream` or `istream` functionality, use `can_ostream` or `can_istream` respectively.
- `can_order`: `operator<=>`, note you probably also want to add `can_equate`, since the compiler cannot generate equality with the `operator<=>` for stronk types.
- `can_equate`: `operator==` with regular equality
- `can_equate_with_is_close`: `operator==` but with numpy's `is_close` definition of equal
Expand All @@ -162,7 +165,8 @@ Skills adds functionality to your stronk types. We have implemented a number of
- `can_iterate` adds the `can_const_iterate` as well implementing `begin()`, `end()`.
- `can_const_index` implements `operator[](const auto&) const` and `at(const auto&) const`
- `can_index` adds the `can_const_index` as well implementing `operator[](const auto&)` and `at(const auto&)`.
- `can_forward_constructor_args` adds a constructor which forwards arguments to the inner class.
- `can_increment` adds both `operator++` operators.
- `can_decrement` adds both `operator--` operators.

### Units
- `unit`: enables unit behavior for multiplication and division.
Expand All @@ -189,8 +193,12 @@ In case you want to specialize the resulting type of unit multiplication and div

By default the units are generated with the `stronk_default_prefab` type.

```cpp :file=./examples/specializers_example.cpp:line_end=29
#include <stronk/specializers.h>
```cpp :file=./examples/specializers_example.cpp:line_end=33
#include <cstdint>
#include <type_traits>

#include <stronk/stronk.h>
#include <stronk/unit.h>

// Lets consider the following units:
struct Distance : twig::stronk<Distance, double, twig::unit>
Expand Down
15 changes: 5 additions & 10 deletions benchmarks/src/benchmark_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <random>
#include <sstream>
#include <string>
#include <type_traits>

#include <stronk/prefabs.h>
#include <stronk/stronk.h>
Expand Down Expand Up @@ -35,7 +36,7 @@ template<typename T>
auto default_max_for_random() -> T
{
if constexpr (std::is_floating_point_v<T>) {
return T(1.0);
return T {1.0};
} else {
return std::numeric_limits<T>::max();
}
Expand Down Expand Up @@ -70,18 +71,15 @@ auto rand(T mi, T ma) -> T
template<typename T>
auto rand() -> T
{
return rand<T>(T(0), default_max_for_random<T>());
return rand<T>(T {0}, default_max_for_random<T>());
}

} // namespace details

template<typename T>
struct generate_randomish
{
auto operator()() const -> T
{
return details::rand<T>();
}
auto operator()() const -> T { return details::rand<T>(); }
};
template<>
struct generate_randomish<std::string>
Expand All @@ -99,10 +97,7 @@ struct generate_randomish<std::string>
template<twig::stronk_like T>
struct generate_randomish<T>
{
auto operator()() const -> T
{
return T {generate_randomish<typename T::underlying_type> {}()};
}
auto operator()() const -> T { return T {generate_randomish<typename T::underlying_type> {}()}; }
};

template<typename T>
Expand Down
17 changes: 14 additions & 3 deletions benchmarks/src/construction_benchmarks.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>

#include <benchmark/benchmark.h>

#include "./benchmark_helpers.h"

namespace
{
template<typename T>
static void benchmark_default_onto_reserved_vector(benchmark::State& state)
void benchmark_default_onto_reserved_vector(benchmark::State& state)
{
auto vec = std::vector<T>(static_cast<size_t>(state.range(0)));
benchmark::DoNotOptimize(vec.data());
Expand All @@ -17,6 +21,7 @@ static void benchmark_default_onto_reserved_vector(benchmark::State& state)
benchmark::ClobberMemory();
}
}
} // namespace

BENCHMARK_TEMPLATE(benchmark_default_onto_reserved_vector, int8_t)->Range(32ULL, 8ULL << 10ULL);
BENCHMARK_TEMPLATE(benchmark_default_onto_reserved_vector, int8_t_wrapping_type)->Range(32ULL, 8ULL << 10ULL);
Expand All @@ -27,8 +32,10 @@ BENCHMARK_TEMPLATE(benchmark_default_onto_reserved_vector, int64_t_wrapping_type
BENCHMARK_TEMPLATE(benchmark_default_onto_reserved_vector, std::string)->Range(32ULL, 8ULL << 10ULL);
BENCHMARK_TEMPLATE(benchmark_default_onto_reserved_vector, string_wrapping_type)->Range(32ULL, 8ULL << 10ULL);

namespace
{
template<typename T>
static void benchmark_rand_onto_reserved_vector(benchmark::State& state)
void benchmark_rand_onto_reserved_vector(benchmark::State& state)
{
auto vec = std::vector<T>(static_cast<size_t>(state.range(0)));
benchmark::DoNotOptimize(vec.data());
Expand All @@ -39,6 +46,7 @@ static void benchmark_rand_onto_reserved_vector(benchmark::State& state)
benchmark::ClobberMemory();
}
}
} // namespace

BENCHMARK_TEMPLATE(benchmark_rand_onto_reserved_vector, int8_t)->Range(32ULL, 8ULL << 10ULL);
BENCHMARK_TEMPLATE(benchmark_rand_onto_reserved_vector, int8_t_wrapping_type)->Range(32ULL, 8ULL << 10ULL);
Expand All @@ -49,8 +57,10 @@ BENCHMARK_TEMPLATE(benchmark_rand_onto_reserved_vector, int64_t_wrapping_type)->
BENCHMARK_TEMPLATE(benchmark_rand_onto_reserved_vector, std::string)->Range(32ULL, 8ULL << 10ULL);
BENCHMARK_TEMPLATE(benchmark_rand_onto_reserved_vector, string_wrapping_type)->Range(32ULL, 8ULL << 10ULL);

namespace
{
template<typename T>
static void benchmark_copy_vector_of(benchmark::State& state)
void benchmark_copy_vector_of(benchmark::State& state)
{
auto vec = std::vector<T>(static_cast<size_t>(state.range(0)));
std::generate(vec.begin(), vec.end(), []() { return generate_randomish<T> {}(); });
Expand All @@ -61,6 +71,7 @@ static void benchmark_copy_vector_of(benchmark::State& state)
benchmark::ClobberMemory();
}
}
} // namespace

BENCHMARK_TEMPLATE(benchmark_copy_vector_of, int8_t)->Range(32ULL, 8ULL << 10ULL);
BENCHMARK_TEMPLATE(benchmark_copy_vector_of, int8_t_wrapping_type)->Range(32ULL, 8ULL << 10ULL);
Expand Down
38 changes: 27 additions & 11 deletions benchmarks/src/unit_benchmarks.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <vector>

#include <benchmark/benchmark.h>
#include <fmt/core.h>

#include "./benchmark_helpers.h"

namespace
{
template<typename T>
static void benchmark_add_units(benchmark::State& state)
void benchmark_add_units(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<T>(static_cast<size_t>(state.range(0)));
std::generate(vec_a.begin(), vec_a.end(), []() { return generate_randomish<T> {}(); });
std::generate(vec_b.begin(), vec_b.end(), []() { return generate_randomish<T> {}(); });
std::ranges::generate(vec_a, []() { return generate_randomish<T> {}(); });
std::ranges::generate(vec_b, []() { return generate_randomish<T> {}(); });

for (auto _ : state) {
for (auto i = 0ULL; i < static_cast<size_t>(state.range(0)); i++) {
Expand All @@ -23,7 +29,7 @@ static void benchmark_add_units(benchmark::State& state)
}

template<typename T, size_t WidthV>
static void benchmark_add_units_simd(benchmark::State& state)
void benchmark_add_units_simd(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<T>(static_cast<size_t>(state.range(0)));
Expand All @@ -42,6 +48,7 @@ static void benchmark_add_units_simd(benchmark::State& state)
}
}
}
} // namespace

// // benchmark_add_units
BENCHMARK_TEMPLATE(benchmark_add_units, int8_t)->Arg(8192);
Expand All @@ -63,8 +70,10 @@ BENCHMARK_TEMPLATE(benchmark_add_units_simd, int64_t_wrapping_type, 32)->Arg(819
BENCHMARK_TEMPLATE(benchmark_add_units_simd, double, 32)->Arg(8192 / 32);
BENCHMARK_TEMPLATE(benchmark_add_units_simd, double_wrapping_type, 32)->Arg(8192 / 32);

namespace
{
template<typename T>
static void benchmark_subtract_units(benchmark::State& state)
void benchmark_subtract_units(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<T>(static_cast<size_t>(state.range(0)));
Expand All @@ -82,7 +91,7 @@ static void benchmark_subtract_units(benchmark::State& state)
}

template<typename T, size_t WidthV>
static void benchmark_subtract_units_simd(benchmark::State& state)
void benchmark_subtract_units_simd(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<T>(static_cast<size_t>(state.range(0)));
Expand All @@ -101,6 +110,7 @@ static void benchmark_subtract_units_simd(benchmark::State& state)
}
}
}
} // namespace

BENCHMARK_TEMPLATE(benchmark_subtract_units, int8_t)->Arg(8192);
BENCHMARK_TEMPLATE(benchmark_subtract_units, int8_t_wrapping_type)->Arg(8192);
Expand All @@ -121,8 +131,10 @@ BENCHMARK_TEMPLATE(benchmark_subtract_units_simd, int64_t_wrapping_type, 32)->Ar
BENCHMARK_TEMPLATE(benchmark_subtract_units_simd, double, 32)->Arg(8192 / 32);
BENCHMARK_TEMPLATE(benchmark_subtract_units_simd, double_wrapping_type, 32)->Arg(8192 / 32);

namespace
{
template<typename T, typename O>
static void benchmark_multiply_units(benchmark::State& state)
void benchmark_multiply_units(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<O>(static_cast<size_t>(state.range(0)));
Expand All @@ -141,7 +153,7 @@ static void benchmark_multiply_units(benchmark::State& state)
}

template<typename T, typename O, size_t WidthV>
static void benchmark_multiply_units_simd(benchmark::State& state)
void benchmark_multiply_units_simd(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<O>(static_cast<size_t>(state.range(0)));
Expand All @@ -161,6 +173,7 @@ static void benchmark_multiply_units_simd(benchmark::State& state)
}
}
}
} // namespace

BENCHMARK_TEMPLATE(benchmark_multiply_units, int8_t, int8_t)->Arg(8192);
BENCHMARK_TEMPLATE(benchmark_multiply_units, int8_t_wrapping_type, int8_t_wrapping_type)->Arg(8192);
Expand Down Expand Up @@ -192,8 +205,10 @@ BENCHMARK_TEMPLATE(benchmark_multiply_units_simd, int64_t_wrapping_type, double_
BENCHMARK_TEMPLATE(benchmark_multiply_units_simd, double, int64_t, 32)->Arg(8192 / 32);
BENCHMARK_TEMPLATE(benchmark_multiply_units_simd, double_wrapping_type, int64_t_wrapping_type, 32)->Arg(8192 / 32);

namespace
{
template<typename T, typename O>
static void benchmark_divide_units(benchmark::State& state)
void benchmark_divide_units(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<O>(static_cast<size_t>(state.range(0)));
Expand All @@ -212,7 +227,7 @@ static void benchmark_divide_units(benchmark::State& state)
}

template<typename T, typename O, size_t WidthV>
static void benchmark_divide_units_simd(benchmark::State& state)
void benchmark_divide_units_simd(benchmark::State& state)
{
auto vec_a = std::vector<T>(static_cast<size_t>(state.range(0)));
auto vec_b = std::vector<O>(static_cast<size_t>(state.range(0)));
Expand All @@ -232,6 +247,7 @@ static void benchmark_divide_units_simd(benchmark::State& state)
}
}
}
} // namespace

BENCHMARK_TEMPLATE(benchmark_divide_units, int8_t, int8_t)->Arg(8192);
BENCHMARK_TEMPLATE(benchmark_divide_units, int8_t_wrapping_type, int8_t_wrapping_type)->Arg(8192);
Expand Down
Loading

0 comments on commit d9f6fec

Please sign in to comment.