From 5d9ffddfe118c9f2356a79df63cc2019cdcb16f8 Mon Sep 17 00:00:00 2001 From: Borislav Stanimirov Date: Tue, 16 Jul 2024 19:30:23 +0300 Subject: [PATCH] new library: generator, wip --- include/itlib/generator.hpp | 125 ++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 8 ++- test/t-generator-20.cpp | 5 ++ 3 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 include/itlib/generator.hpp create mode 100644 test/t-generator-20.cpp diff --git a/include/itlib/generator.hpp b/include/itlib/generator.hpp new file mode 100644 index 0000000..fc08b90 --- /dev/null +++ b/include/itlib/generator.hpp @@ -0,0 +1,125 @@ +// itlib-generator v1.00 +// +// Simple coroutine generator class for C++20 and later +// +// SPDX-License-Identifier: MIT +// MIT License: +// Copyright(c) 2024 Borislav Stanimirov +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files(the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and / or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions : +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// VERSION HISTORY +// +// 1.00 (2024-07-xx) Initial release +// +// +// DOCUMENTATION +// +// Simply include this file wherever you need. +// It defines the class generator which allows you to write simple coroutine- +// based generators. +// +// Example: +// +// itlib::generator range(int begin, int end) { +// for (int i = begin; i < end; ++i) { +// co_yield i; +// } +// } +// ... +// for (int i : range(0, 10)) { +// std::cout << i << std::endl; +// } +// +// TESTS +// +// You can find unit tests in the official repo: +// https://github.com/iboB/itlib/blob/master/test/ +// +#pragma once +#include +#include +#include + +namespace itlib { + +namespace genimpl { +// tempting to include expected here so we could have optional of ref and +// ditch the T& specialization +// ... but we promised to make standalone libs + +template +class val_holder : public std::optional {}; + +template +class val_holder { + T* val = nullptr; +public: + void emplace(T& v) noexcept { val = &v; } + void reset() noexcept { val = nullptr; } + T& operator*() noexcept { return *val; } + bool has_value() const noexcept { return val != nullptr; } + explicit operator bool() const noexcept { return has_value(); } +}; + +} // namespace genimpl + +template +class generator { +public: + using value_ret_t = std::conditional_t, T, const T&>; + + class promise_type { + genimpl::val_holder m_val; + public: + promise_type() noexcept = default; + + ~promise_type() = default; + generator get_return_object() noexcept { + return generator{std::coroutine_handle::from_promise(*this)}; + } + std::suspend_always initial_suspend() noexcept { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + std::suspend_always yield_value(T value) noexcept { // assume T is noexcept move constructible + m_val = std::move(value); + return {}; + } + void return_void() noexcept {} + void unhandled_exception() { throw; } + + value_ret_t val() const noexcept { + return *m_val; + } + }; + + ~generator() { + if (m_handle) m_handle.destroy(); + } + + // std::optional interface + genimpl::val_holder next() {} +private: + using handle_t = std::coroutine_handle; + handle_t m_handle; + explicit generator(handle_t handle) noexcept : m_handle(handle) {} +}; + +} // namespace itlib diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a09435c..916732f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,9 +1,12 @@ +# Copyright (c) Borislav Stanimirov +# SPDX-License-Identifier: MIT +# cmake_minimum_required(VERSION 3.16 FATAL_ERROR) include(./get_cpm.cmake) -CPMAddPackage(gh:iboB/icm@1.4.4) -CPMAddPackage(gh:iboB/doctest-util@0.1.1) +CPMAddPackage(gh:iboB/icm@1.5.1) +CPMAddPackage(gh:iboB/doctest-util@0.1.2) include(${icm_SOURCE_DIR}/icm_build_failure_testing.cmake) @@ -58,6 +61,7 @@ add_itlib_test(dynamic_bitset) add_itlib_test(expected) add_itlib_test(flat_map) add_itlib_test(flat_set) +add_itlib_test(generator) add_itlib_test(make_ptr) add_itlib_test(memory_view) add_itlib_test(mem_streambuf) diff --git a/test/t-generator-20.cpp b/test/t-generator-20.cpp new file mode 100644 index 0000000..f12f8f1 --- /dev/null +++ b/test/t-generator-20.cpp @@ -0,0 +1,5 @@ +// Copyright (c) Borislav Stanimirov +// SPDX-License-Identifier: MIT +// +#include +#include \ No newline at end of file