Skip to content

Commit

Permalink
Fixes #682: poor_mans_option::value_or() is now const
Browse files Browse the repository at this point in the history
  • Loading branch information
eyalroz committed Sep 21, 2024
1 parent b3a18cf commit 443d6ab
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
126 changes: 126 additions & 0 deletions src/cuda/api/detail/marshalled_options.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#ifndef SRC_CUDA_API_DETAIL_MARSHALLED_OPTIONS_HPP_
#define SRC_CUDA_API_DETAIL_MARSHALLED_OPTIONS_HPP_

#include "../types.hpp"

#include <cstdlib>
#include <vector>
#include <string>
#include <cstring>
#include <sstream>
#include <algorithm>

namespace cuda {

namespace rtc {

namespace detail_ {

// These two structs are streamed to a marshalled options object (see below)
// to indicate the start of a new option or the conclusion of all options,
// respectively

template <typename Delimiter> struct opt_start_t;

template<typename T>
struct is_marshalling_control : ::std::false_type {};

/**
* This class is necessary for realizing everything we need from
* the marshalled options: Easy access using an array of pointers,
* for the C API - and RAIIness for convenience and safety when
* using the wrapper classes.
*/
class marshalled_options_t {
public:
using size_type = size_t;

struct advance_gadget {}; /// triggers an advance() when streamed into an object of this class

marshalled_options_t()
{
option_positions.push_back(0);
}
marshalled_options_t(size_type max_num_options)
{
option_positions.reserve(max_num_options);
option_positions.push_back(0);
}

marshalled_options_t(const marshalled_options_t&) = delete;
marshalled_options_t(marshalled_options_t&&) = default;

protected:
mutable ::std::ostringstream oss;
mutable ::std::string finalized {};
::std::vector<size_type> option_positions;
// Offsets into the eventually-created options string.
// Note that the last offset is to a not-yet-existing option
public:

bool empty() const {
return oss.tellp() == 0;
}

template <typename T, typename = ::cuda::detail_::enable_if_t<not detail_::is_marshalling_control<typename ::std::decay<T>::type>::value>>
marshalled_options_t& operator<<(T&& x)
{
oss << x;
return *this;
}

marshalled_options_t& advance()
{
oss << '\0';
option_positions.push_back(oss.tellp());
return *this;
}

::std::vector<const char*> option_ptrs() const {
finalized = oss.str();
auto ptrs = ::std::vector<const char*>();
ptrs.reserve(option_positions.size()-1);
const char* start = finalized.data();
::std::transform(option_positions.cbegin(), option_positions.cend() - 1, ::std::back_inserter(ptrs),
[start] (size_type pos){ return start + pos; });
return ptrs;
}
};

inline marshalled_options_t& operator<< (marshalled_options_t& mo, marshalled_options_t::advance_gadget)
{
mo.advance();
return mo;
}

template<> struct is_marshalling_control<marshalled_options_t::advance_gadget> : ::std::true_type {};

template<typename Delimiter>
struct is_marshalling_control<opt_start_t<Delimiter>> : ::std::true_type {};

template <typename Delimiter>
struct opt_start_t {
bool ever_used;
Delimiter delimiter_;

opt_start_t(Delimiter delimiter) : ever_used(false), delimiter_(delimiter){ }
};

template <typename MarshalTarget, typename Delimiter>
MarshalTarget& operator<<(MarshalTarget& mt, detail_::opt_start_t<Delimiter>& opt_start)
{
if (not opt_start.ever_used) {
opt_start.ever_used = true;
}
else {
mt << opt_start.delimiter_;
}
return mt;
}
} // namespace detail_

} // namespace rtc

} // namespace cuda

#endif /* SRC_CUDA_API_DETAIL_MARSHALLED_OPTIONS_HPP_ */
2 changes: 1 addition & 1 deletion src/cuda/api/detail/optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ struct poor_mans_optional {
{ return maybe_value.value; }

template<typename U>
T value_or(U&& fallback_value)
T value_or(U&& fallback_value) const
{
return has_value_ ? maybe_value.value : static_cast<T>(::std::forward<U>(fallback_value));
}
Expand Down

0 comments on commit 443d6ab

Please sign in to comment.