Skip to content

Instantly share code, notes, and snippets.

@Liareth
Created October 30, 2015 13:18
Show Gist options
  • Save Liareth/ed828818c190491e7817 to your computer and use it in GitHub Desktop.
Save Liareth/ed828818c190491e7817 to your computer and use it in GitHub Desktop.
#include <stack>
#include <tuple>
#include <string>
#include <cstdint>
#include <array>
#include <cassert>
template <typename T>
class Maybe
{
public:
Maybe(Maybe<T>&& other) = default;
Maybe(Maybe<T>& other) = delete;
Maybe<T> operator=(Maybe<T> const & other) = delete;
explicit Maybe()
: m_HasValue(false), m_Data()
{
}
explicit Maybe(T&& data)
: m_HasValue(true), m_Data(data)
{
}
T& operator*()
{
return m_Data;
}
T extract()
{
m_HasValue = false;
return std::move(m_Data);
}
operator bool() const
{
return m_HasValue;
}
private:
bool m_HasValue;
T m_Data;
};
constexpr uint8_t TYPE_SIZE_IN_CHARACTERS = 2;
static_assert(TYPE_SIZE_IN_CHARACTERS >= 1, "The type size was invalid!");
enum class NWNTypes : uint8_t
{
INT = 0,
FLOAT,
OBJECT,
STRING = 11, // Double character test!
COUNT,
LIMIT = 100, // Limited to two characters -- e.g. up to 99
// Could delimit by a space any have a scaling count (up to type size),
// but this is slower as it requires an allocation in ExtractType.
};
NWNTypes ExtractType(std::string const& data)
{
std::array<char, TYPE_SIZE_IN_CHARACTERS + 1> buffer; // + 1 for null term
memcpy(buffer.data(), data.c_str(), TYPE_SIZE_IN_CHARACTERS);
buffer[TYPE_SIZE_IN_CHARACTERS] = '\0';
return static_cast<NWNTypes>(std::strtol(buffer.data(), nullptr, 10));
}
template <typename T, typename = std::enable_if<std::is_pointer<T>::value>>
Maybe<T> nwnx_cast(std::string&& data)
{
using MaybeTempl = Maybe<T>;
return MaybeTempl(reinterpret_cast<T>(data.c_str() + TYPE_INDEX_INTO_DATA));
}
template <>
Maybe<int> nwnx_cast<int>(std::string&& data)
{
using MaybeTempl = Maybe<int>;
NWNTypes const type = ExtractType(data);
return type == NWNTypes::INT ? MaybeTempl(std::strtol(data.c_str() + TYPE_SIZE_IN_CHARACTERS - 1, nullptr, 10)) : MaybeTempl();
}
template <>
Maybe<std::string> nwnx_cast<std::string>(std::string&& data)
{
using MaybeTempl = Maybe<std::string>;
NWNTypes const type = ExtractType(data);
data.erase(0, TYPE_SIZE_IN_CHARACTERS); // Strip the type info.
return type == NWNTypes::STRING ? MaybeTempl(std::forward<std::string>(data)) : MaybeTempl();
}
template <typename T>
Maybe<std::tuple<T>> MakeTupleFromArgs(std::stack<std::string>& arguments)
{
using MaybeTempl = Maybe<std::tuple<T>>;
auto data = nwnx_cast<T>(std::move(arguments.top()));
arguments.pop();
return data ? MaybeTempl(std::make_tuple(data.extract())) : MaybeTempl();
}
template <typename T1, typename T2, typename ... Ts>
Maybe<std::tuple<T1, T2, Ts ...>> MakeTupleFromArgs(std::stack<std::string>& arguments)
{
using MaybeTempl = Maybe<std::tuple<T1, T2, Ts ...>>;
auto first = MakeTupleFromArgs<T1>(arguments);
auto others = MakeTupleFromArgs<T2, Ts...>(arguments);
return first && others ? MaybeTempl(std::tuple_cat(first.extract(), others.extract())) : MaybeTempl();
}
template <typename ... Params>
Maybe<std::tuple<Params...>> ExtractArgs(std::stack<std::string>& arguments)
{
using MaybeTempl = Maybe<std::tuple<Params...>>;
constexpr size_t paramCount = sizeof...(Params);
if (arguments.size() != paramCount)
{
return MaybeTempl();
}
auto data = MakeTupleFromArgs<Params...>(arguments);
assert(arguments.empty()); // Logically, arguments should now be empty.
return MaybeTempl(std::move(data));
}
int main()
{
std::stack<std::string> arguments;
arguments.push("0 0");
arguments.push("0 1");
arguments.push("1 2"); // Type wrong.
arguments.push("0 3");
auto data = ExtractArgs<int, int, int, int>(arguments); // Fails because type wrong.
auto data2 = ExtractArgs<int, int, int, int>(arguments); // Fails because argument count invalid.
arguments.push("0 0");
arguments.push("0 1");
arguments.push("0 2");
auto data3 = ExtractArgs<int, int, int>(arguments); // Succeeds.
arguments.push("11HelloThisIsATest");
arguments.push("11IsTheMicOn?");
arguments.push("0 5");
arguments.push("11Bottles of beers on the wall!!!");
auto data4 = ExtractArgs<std::string, int, std::string, std::string>(arguments); // Note the order.
// The last pushed to the stack = the first consumed in the template list.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment