Compiler optimizes out the coroutine value - c++

I have implemented two coroutines that uses the Resumable class:
#include <coroutine>
#include <future>
#include <iostream>
class Resumable
{
public:
class promise_type
{
public:
auto initial_suspend()
{
return std::suspend_always();
}
auto final_suspend() noexcept
{
return std::suspend_always();
}
auto yield_value(const int& value)
{
value_ = value;
return std::suspend_always();
}
auto return_value(const int& value)
{
value_ = value;
return std::suspend_always();
}
auto get_return_object()
{
return std::coroutine_handle<promise_type>::from_promise(*this);
}
void unhandled_exception()
{
}
public:
int value_;
};
public:
Resumable(std::coroutine_handle<promise_type> handle)
: handle_{ handle }
{
}
~Resumable()
{
handle_.destroy();
}
int get()
{
if (!handle_.done())
{
handle_.resume();
}
return handle_.promise().value_;
}
private:
std::coroutine_handle<promise_type> handle_;
};
Resumable generate(int a)
{
for (int i = 1; i < a; ++i)
{
co_yield i;
}
co_return 0;
}
Resumable n_generate(int a)
{
auto gen = generate(a);
for (auto value = gen.get(); value != 0; value = gen.get())
{
//std::cout << -value << std::endl; <-- uncommenting this fixes the problem
co_yield -value;
}
co_return 0;
}
int main(int argc, const char* argv[])
{
auto gen_10 = n_generate(10);
for (auto value = gen_10.get(); value != 0; value = gen_10.get())
{
std::cout << value << std::endl;
}
return 0;
}
The output for this code is empty.
If I uncomment the line marked line in n_generate, the output will be:
-1
-1
-2
-2
-3
-3
-4
-4
-5
-5
-6
-6
-7
-7
-8
-8
-9
-9
How can I pass the negative values to main without printing them in n_generate function?
I am using gcc-10 on Ububtu 20.04.
Additional flags in my makefile:
LDLIBS := -lstdc++
CXXFLAGS := -g -std=c++2a -fcoroutines

Related

Create a generator in C++ using coroutines

Following the McNellis's presentation for coroutines(Introduction to C Coroutines), I try to compile the example of the simple coroutine, which actually is a simple counter.
However when the resume is called ,assertion is fired.
Specifically
_LIBCPP_ASSERT(!done(),
"resume() has undefined behaviour when the coroutine is done");
I have not much experience with coroutines and I cannot find out what goes wrong.
The code is below
#include <iostream>
#include <coroutine>
using namespace std;
//using namespace experimental;
struct resumable_thing
{
struct promise_type
{
int const* _current;
promise_type & get_return_object() noexcept
{
return *this;
}
auto initial_suspend() { return suspend_always{}; }
auto final_suspend() { return suspend_always{}; }
auto yield_value(int const& value) {
_current = &value;
return suspend_always{};
}
void unhandled_exception()
{
auto ex = std::current_exception();
std::rethrow_exception(ex);
//// MSVC bug? should be possible to rethrow with "throw;"
//// rethrow exception immediately
// throw;
}
void return_void() noexcept
{
}
};
// using coroutine_handle = coroutine_handle<promise_type>;
resumable_thing() = default;
resumable_thing(resumable_thing const & ) = delete;
resumable_thing & operator = (resumable_thing const & ) =delete;
resumable_thing(promise_type && promise)
: _coroutine(coroutine_handle<promise_type>::from_promise(promise)) {}
resumable_thing(resumable_thing&& other) : _coroutine(other._coroutine)
{
other._coroutine = nullptr;
}
resumable_thing & operator = (resumable_thing const && other)
{
_coroutine = other._coroutine;
_coroutine = nullptr;
return *this;
}
explicit resumable_thing(coroutine_handle<promise_type> coroutine)
:_coroutine(coroutine)
{
}
~resumable_thing()
{
if(_coroutine)
{
_coroutine.destroy();
}
}
void resume()
{
std::cout << "coroutines resume" << std::endl;
_coroutine.resume();
}
coroutine_handle<promise_type> _coroutine = nullptr;
};
resumable_thing counter()
{
cout << "counter: called\n";
for(int i = 0 ; ++i;)
{
co_await suspend_always{};
cout << "counter: resumed (#" << i << ")\n";
}
}
int main(int argc, const char * argv[]) {
// insert code here...
cout << "main: calling counter\n";
resumable_thing the_counter = counter();
cout << "main: resuming counter\n";
the_counter.resume();//assertion is fired
cout << "main:done" << std::endl;
return 0;
}
Please find the code here
promise_type::get_return_object() shall return user-defined coroutine result type resumable_thing, instead of promise_type& itself.
struct resumable_thing
{
struct promise_type
{
resumable_thing get_return_object() noexcept
{
return {*this};
}
// ...
};
resumable_thing(promise_type & promise)
: _coroutine(coroutine_handle<promise_type>::from_promise(promise)) {}
// ...
};
And resumable_thing's move assignment operator resets this->_coroutine unintentionally.
// FIXED: resumable_thing const && -> resumable_thing &&
resumable_thing & operator = (resumable_thing && other)
{
_coroutine = other._coroutine;
// FIXED: _coroutine -> other._coroutine
other._coroutine = nullptr;
return *this;
}

Getting Permutations with Repetitions in this special way

I have a list of {a,b} and i need all possible combinatations where say n=3.
so:
[a,b,a],
[b,a,b]
[a,a,a]
[b,b,b]
etc.
Is there a name of such a problem
My current solution just uses random sampling and is very inefficient:
void set_generator(const vector<int>& vec, int n){
map<string, vector<int>> imap;
int rcount = 0;
while(1){
string ms = "";
vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
cout << ms << endl;
}
}
set_generator({1,2},3);
Let us call b the size of the input vector.
The problem consists in generating all numbers from 0 to b^n - 1, in base b.
A simple solution increments the elements of an array one by one, each from 0 to b-1.
This is performed by the function increment in the code hereafter.
Output:
111
211
121
221
112
212
122
222
The code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
void set_generator_op (const std::vector<int>& vec, int n){
std::map<std::string, std::vector<int>> imap;
int rcount = 0;
while(1){
std::string ms = "";
std::vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
std::cout << ms << "\n";
}
}
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
void set_generator_new (const std::vector<int>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
while (true) {
std::string permut = "";
for (auto &k: cpt) {
permut += std::to_string (vec[k]);
}
std::cout << permut << "\n";
if (!increment(cpt, base)) return;
}
}
int main() {
set_generator_op ({1,2},3);
std::cout << "\n";
set_generator_new ({1,2},3);
}
Following advices of Jarod42, I have
suppressed the useless conversion to a string
used a more elegant do ... while instead of the while true
inversed the iterators for printing the result
Moreover, I have created a templated version of the program.
New output:
111
112
121
122
211
212
221
222
aaa
aab
aba
abb
baa
bab
bba
bbb
And the new code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
template <typename T>
void set_generator_new (const std::vector<T>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
do {
for (auto it = cpt.rbegin(); it != cpt.rend(); ++it) {
std::cout << vec[*it];
}
std::cout << "\n";
} while (increment(cpt, base));
}
int main() {
set_generator_new<int> ({1,2}, 3);
std::cout << "\n";
set_generator_new<char> ({'a','b'}, 3);
}
Besides the concrete answer for integer usage, I want to provide a generic way I needed during test case construction for scenarios with a wide spread of various parameter variations. Maybe it's helpful to you too, at least for similar scenarios.
#include <vector>
#include <memory>
class SingleParameterToVaryBase
{
public:
virtual bool varyNext() = 0;
virtual void reset() = 0;
};
template <typename _DataType, typename _ParamVariationContType>
class SingleParameterToVary : public SingleParameterToVaryBase
{
public:
SingleParameterToVary(
_DataType& param,
const _ParamVariationContType& valuesToVary) :
mParameter(param)
, mVariations(valuesToVary)
{
if (mVariations.empty())
throw std::logic_error("Empty variation container for parameter");
reset();
}
// Step to next parameter value, return false if end of value vector is reached
virtual bool varyNext() override
{
++mCurrentIt;
const bool finished = mCurrentIt == mVariations.cend();
if (finished)
{
return false;
}
else
{
mParameter = *mCurrentIt;
return true;
}
}
virtual void reset() override
{
mCurrentIt = mVariations.cbegin();
mParameter = *mCurrentIt;
}
private:
typedef typename _ParamVariationContType::const_iterator ConstIteratorType;
// Iterator to the actual values this parameter can yield
ConstIteratorType mCurrentIt;
_ParamVariationContType mVariations;
// Reference to the parameter itself
_DataType& mParameter;
};
class GenericParameterVariator
{
public:
GenericParameterVariator() : mFinished(false)
{
reset();
}
template <typename _ParameterType, typename _ParameterVariationsType>
void registerParameterToVary(
_ParameterType& param,
const _ParameterVariationsType& paramVariations)
{
mParametersToVary.push_back(
std::make_unique<SingleParameterToVary<_ParameterType, _ParameterVariationsType>>(
param, paramVariations));
}
const bool isFinished() const { return mFinished; }
void reset()
{
mFinished = false;
mNumTotalCombinationsVisited = 0;
for (const auto& upParameter : mParametersToVary)
upParameter->reset();
}
// Step into next state if possible
bool createNextParameterPermutation()
{
if (mFinished || mParametersToVary.empty())
return false;
auto itPToVary = mParametersToVary.begin();
while (itPToVary != mParametersToVary.end())
{
const auto& upParameter = *itPToVary;
// If we are the very first configuration at all, do not vary.
const bool variedSomething = mNumTotalCombinationsVisited == 0 ? true : upParameter->varyNext();
++mNumTotalCombinationsVisited;
if (!variedSomething)
{
// If we were not able to vary the last parameter in our list, we are finished.
if (std::next(itPToVary) == mParametersToVary.end())
{
mFinished = true;
return false;
}
++itPToVary;
continue;
}
else
{
if (itPToVary != mParametersToVary.begin())
{
// Reset all parameters before this one
auto itBackwd = itPToVary;
do
{
--itBackwd;
(*itBackwd)->reset();
} while (itBackwd != mParametersToVary.begin());
}
return true;
}
}
return true;
}
private:
// Linearized parameter set
std::vector<std::unique_ptr<SingleParameterToVaryBase>> mParametersToVary;
bool mFinished;
size_t mNumTotalCombinationsVisited;
};
Possible usage:
GenericParameterVariator paramVariator;
size_t param1;
int param2;
char param3;
paramVariator.registerParameterToVary(param1, std::vector<size_t>{ 1, 2 });
paramVariator.registerParameterToVary(param2, std::vector<int>{ -1, -2 });
paramVariator.registerParameterToVary(param3, std::vector<char>{ 'a', 'b' });
std::vector<std::tuple<size_t, int, char>> visitedCombinations;
while (paramVariator.createNextParameterPermutation())
visitedCombinations.push_back(std::make_tuple(param1, param2, param3));
Generates:
(1, -1, 'a')
(2, -1, 'a')
(1, -2, 'a')
(2, -2, 'a')
(1, -1, 'b')
(2, -1, 'b')
(1, -2, 'b')
(2, -2, 'b')
For sure, this can be further optimized/specialized. For instance you can simply add a hashing scheme and/or an avoid functor if you want to avoid effective repetitions. Also, since the parameters are held as references, one might consider to protect the generator from possible error-prone usage via deleting copy/assignement constructors and operators.
Time complexity is within the theoretical permutation complexity range.

Looping without a loop

We have been restricted us to not use a loop in a program as a programming challenge.
Restrictions:
You can not use while, for, goto and recursion.
The restrictions are pretty daunting. I couldn't really think of any proper solution.
So I opted for this one which is achieved by modifying the return address.
Could this be any better?
#include <unistd.h>
#include <sys/mman.h>
#include <iostream>
#include <cstring>
void the__(){}
void magic__(){}
void loop__(){}
void function__(){}
void here__(){}
template <typename T>
struct for_
{
bool started = false;
void* fix = nullptr;
void(*body)(T&) = nullptr;
for_(void(*body)(T&))
: body(body)
{
auto do_for__ = uintptr_t(do_for_);
uint64_t magic[] = {5243466812662057800, 6135086863767628931ull, 10416984888688609608ull, 144};
mprotect((void*)(do_for__-do_for__%4096), 4096, 7);
std::memcpy((void*)(do_for__+135), magic, 25);
}
static void do_for_(T& ctx)
{
void** p = (void**)((char*)&p+16);
if (!ctx.started)
{
if (!ctx) return;
ctx.started = true;
ctx.fix = *p;
*p = (void*)do_for_;
}
ctx.body(ctx);
ctx.next();
if (ctx)
{
the__();
magic__();
loop__();
function__();
here__();
}
else
{
*p = ctx.fix;
}
}
};
struct For0ToN : for_<For0ToN>
{
For0ToN(int N, void(*f)(For0ToN&))
: for_<For0ToN>(f)
, N(N)
{
do_for_(*this);
}
operator bool() {return i < N;}
operator int() {return i;}
void next() {i++;}
int count() {return i;}
int i = 0, N = 0;
};
int main()
{
For0ToN(10, +[](For0ToN& i)
{
std::cout << int(i) << ": ";
For0ToN(i.count(), +[](For0ToN& i)
{
std::cout << int(i) << ". ";
});
std::cout << "\n";
});
std::cout << "done\n";
return 0;
}
The code is demonstrated here: https://coliru.stacked-crooked.com/a/3dd77ade501ac748
You could use longjmp. Here's an example from cppreference:
#include <csetjmp>
#include <iostream>
std::jmp_buf jump_buffer;
[[noreturn]] void a(int count)
{
std::cout << "a(" << count << ") called\n";
std::longjmp(jump_buffer, count+1); // setjmp() will return count+1
}
int main() {
// loop from 0-9
volatile int count = 0; // local variables must be volatile for setjmp
if (setjmp(jump_buffer) != 10) {
a(count++); // This will cause setjmp() to exit
}
}
Question is unclear but 1 alternative of the loop is std::transform()
Template metaprogramming is common way of avoiding writing explicit loop in code. This work gets done by compiler. Check this for examples of factorial and bubble sort implementation without writing explicit loops. You can check this stack overflow post as well.
Does it count if I hide recursion into function objects and create a finite state machine?
struct state
{
size_t current_column;
size_t current_row;
size_t max_column;
size_t max_row;
};
typedef function<void(state&)> action_t;
struct do_item
{
do_item(ostream& ss, action_t* move_next)
: ss_(ss), move_next_(move_next) {}
void operator()(state& s)
{
if (s.current_row == s.max_row)
{
ss_ << "done";
return;
}
if (0 == s.current_column)
{
ss_ << s.current_row << ':';
}
if (s.max_column == s.current_column)
{
ss_ << '\n';
s.current_column = 0;
++s.current_row;
s.max_column = s.current_row;
}
else
{
ss_ << ' ' << s.current_column << '.';
++s.current_column;
}
(*move_next_)(s);
}
ostream& ss_;
action_t* move_next_;
};
static string no_loops_challenge(size_t n)
{
stringstream ss;
state s = {0, 0, 0, n};
action_t move_next;
do_item action(ss, &move_next);
move_next = action;
action(s);
return ss.str();
}
Here's a solution using range-v3 that should satisfy all the constraints:
namespace rv = ranges::views;
ranges::for_each(rv::iota(0, 10), [](int i) {
std::cout << i << ": ";
ranges::copy(rv::iota(0, i),
ranges::ostream_iterator<int>(std::cout, ". "));
std::cout << "\n";
});
Here's a demo.

template argument was not declared in this scope

Why am I having issues compiling this in g++ 4.8.5, -std=c++11 -O2 -lm?
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <numeric>
#include <sstream>
#include <utility>
template<uint_fast32_t N>
class Jollo
{
private:
template<uint_fast32_t c>
struct Player
{
int_fast32_t cards[c]; // This line is OK!
uint_fast32_t nsize = c; // error 'c' was not declared in this scope
friend std::istream& operator>>(std::istream& is, Player& p)
{
for(auto& i : p.cards){
is >> i;
}
return is;
}
};
private:
enum JP_ID{ JPID_PRINCE = N+1, JPID_PRINCESS, JPID_NONE };
Player<2> m_Prince;
Player<3> m_Princess;
int_fast32_t deck[N];
constexpr static int_fast32_t RoundsToWin {2};
int_fast32_t NextAvailableCard(const JP_ID& idPlayer, int_fast32_t lastPlayedCard = 0);
public:
Jollo<N>(){
static_assert( N>4, "Invalid deck size - JolloManager");
}
bool Read();
int_fast32_t GetWinningCard();
};
template<uint_fast32_t N>
bool Jollo<N>::Read()
{
static std::string line;
std::getline(std::cin, line);
std::istringstream issline(line);
issline >> m_Princess;
issline >> m_Prince;
return (m_Princess.cards[0] != 0);
}
template<uint_fast32_t N>
int_fast32_t Jollo<N>::NextAvailableCard(const JP_ID& idPlayer, int_fast32_t lastPlayedCard)
{
if(idPlayer == JPID_PRINCE)
{
for(int_fast32_t i{0}; i<m_Prince.nsize; ++i) {
if(deck[m_Prince.cards[i] - 1] != JPID_PRINCE){
deck[m_Prince.cards[i] - 1] = JPID_PRINCE;
return m_Prince.cards[i];
}
}
} else
if(idPlayer == JPID_PRINCESS)
{
for(int_fast32_t i{0}; i<m_Princess.nsize; ++i) {
if(deck[m_Princess.cards[i] - 1] != JPID_PRINCESS && deck[m_Princess.cards[i] - 1] > lastPlayedCard) {
deck[m_Princess.cards[i] - 1] = JPID_PRINCESS;
return m_Princess.cards[i];
}
}
//no card was higher, return lowest available card
for(int_fast32_t i{0}; i<m_Princess.nsize; ++i) {
if(deck[m_Princess.cards[i] - 1] != JPID_PRINCESS) {
deck[m_Princess.cards[i] - 1] = JPID_PRINCESS;
return m_Princess.cards[i];
}
}
}
for(uint_fast32_t i{0}; i<N; i++)
{
if(deck[i] != JPID_PRINCE && deck[i] != JPID_PRINCESS && deck[i] > lastPlayedCard ) {
return deck[i];
}
}
return -1;
}
template<uint_fast32_t N>
int_fast32_t Jollo<N>::GetWinningCard()
{
std::iota(deck, deck + N, 1);
std::sort(m_Prince.cards, m_Prince.cards + m_Prince.nsize, std::greater<int_fast32_t>());
std::sort(m_Princess.cards, m_Princess.cards + m_Princess.nsize);
int_fast32_t princeWins {0};
int_fast32_t princessWins {0};
for(int_fast32_t round {0}; round < RoundsToWin; ++round) //play two first rounds
{
int_fast32_t princeCard = NextAvailableCard(JPID_PRINCE);
int_fast32_t princessCard = NextAvailableCard(JPID_PRINCESS, princeCard);
if(princessCard > princeCard){
++princessWins;
} else {
++princeWins;
}
}
int_fast32_t lastPrincessCard = NextAvailableCard(JPID_PRINCESS); //important to flip the last card on the deck before continuing
if(princessWins == RoundsToWin){
return -1;
}
if(princeWins == RoundsToWin){
return NextAvailableCard(JPID_NONE);
}
return NextAvailableCard(JPID_NONE, lastPrincessCard);
}
int main()
{
Jollo<52u> jollo;
while(true)
{
if(!jollo.Read()) {
break;
}
std::cout << jollo.GetWinningCard() << '\n';
}
return 0;
}
I can compile it on almost any other g++ version with c++11 flags.
This would seem to be GCC bug 57887, which seems to have been fixed in 4.9.0. I would suggest updating your compiler to something remotely not ancient…
If you cannot update your compiler for some reason (you really should update your compiler), a workaround would seem to be to avoid the in-class member initializer and use the constructor's initializer list instead:
class Jollo
{
private:
template<int c>
struct Player
{
int cards[c];
int nsize;
Player() : nsize(c) {}
};
};
working example here

Cref postincrementation in Map definition

So I have such definition on map class on vector, it works good except for post-incrementation, which doesn't work as it should. You can see in example that variable a should be equal to 10 (post-incremented after assignment). But it's equal to 11. I have no idea how to fix that.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template<class T>
class Map {
class Cref {
friend class Map;
Map& m;
string key;
T value;
public:
operator double() {
return m.read(key);
};
Map::Cref & operator=(double num) {
m.write(key, num);
return *this;
};
Map::Cref & operator++(int) {
Cref c(*this);
m.increment(key, value);
return c;
}
Cref(Map& m, string a)
: m(m),
key(a) {};
};
public:
class Unitialized {};
struct Record {
string key;
T value;
};
vector<Record> data;
Map() {}
~Map() {}
bool ifexist(string k) {
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == k)
return 1;
}
return 0;
}
Cref operator[](string key) {
return Map::Cref( * this, key);
}
private:
void increment(string key, T value) {
if (ifexist(key) == 0) {
throw Unitialized();
}
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == key)
data.at(i).value += 1;
}
}
void write(string key, T value) {
if (ifexist(key) == 1) {
cout << "Element already exist" << endl;
return;
}
Record r;
r.key = key;
r.value = value;
data.push_back(r);
}
double read(string key) {
if (ifexist(key) == 0) {
throw Unitialized();
}
for (int i = 0; i < data.size(); i++) {
if (data.at(i).key == key)
return data.at(i).value;
}
return 0;
}
};
int main(int argc, char** argv) {
Map<int> m;
m["ala"] = 10;
int a = 0;
a = m["ala"]++;
cout << a << endl;
try {
cout << m["ala"] << endl;
cout << m["ola"] << endl;
} catch (Map<int>::Unitialized&) {
cout << "Unitialized element" << endl;
}
return 0;
}
Yes, I already fixed that, overloading of ++ operator should look like that :
T operator ++(int)
{
T ret = m.read(this->key);
m.increment(key, value);
return ret;
}
This fixes everything.