Modern compilers can perform this optimization if you turn it on with a compiler flag. I modified your code to the following, in order to get it to compile on godbolt.org:
#include <algorithm>
#include <stddef.h>
#include <vector>
class EventHandle {
public:
constexpr EventHandle() : dummy(~0U) {}
constexpr auto operator==(const EventHandle& x) const
{
return dummy == x.dummy;
}
private:
unsigned dummy;
};
constexpr EventHandle INVALID_HANDLE = EventHandle();
class Csi {
public:
int GetEventCode(EventHandle) const;
EventHandle FindNextEventEx( EventHandle, const int*, int, size_t ) const;
};
void GetEvents(EventHandle handle, const std::vector<int>& desiredCodes, std::vector<EventHandle>& events, Csi &csi)
{
if (handle == INVALID_HANDLE)
{
return;
}
int code = csi.GetEventCode(handle);
bool codeSatisfiesSearch = (std::find(desiredCodes.begin(), desiredCodes.end(), code) != desiredCodes.end());
if (codeSatisfiesSearch)
{
events.push_back(handle);
handle = csi.FindNextEventEx(handle, &desiredCodes[0], 0, desiredCodes.size());
}
else
{
handle = csi.FindNextEventEx(handle, &desiredCodes[0], 0, desiredCodes.size());
}
return GetEvents(handle, desiredCodes, events, csi);
}
I made only two significant changes. I provided stub class
definitions for EventHandle
and Csi
, so that the compiler would generate code at all. I also changed desiredCodes
and events
to reference parameters, so that the compiler would not make copies. (This changes the semantics: the function now alters the original events
object. You might wish to declare it as std::vector<EventHandle>&& events
to make it more explicit that you clobber the input parameter.) I also added std::
to STL types and algorithms.
MSVC 19.22 x64 optimizes this to tail-recursion if you give it the /Ox
flag. GCC 9.2 x86_64 requires -O2
or higher. Clang 8.0.0 and ICC 19.0.1 both require -O
or higher. For example, with -O
, line 213 of the ICC code listing optimizes to a jmp
.
jmp GetEvents(EventHandle, std::vector<int, std::allocator<int> > const&, std::vector<EventHandle, std::allocator<EventHandle> >&, Csi&) #44.12
Without optimization flags, line 1724 performs a recursive non-tail call.
call GetEvents(EventHandle, std::vector<int, std::allocator<int> > const&, std::vector<EventHandle, std::allocator<EventHandle> >&, Csi&) #44.12