summaryrefslogtreecommitdiffhomepage
path: root/include/ocl/option.hpp
blob: 93e01c760fc25bdd5c57697ec9131669ea27f37d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * File: option.hpp
 * Author: Amlal El Mahrouss,
 * Copyright 2023-2025, Amlal El Mahrouss, Licensed under the Boost Software License
 */

#ifndef __OCL_CORE_OPTION
#define __OCL_CORE_OPTION

#include <ocl/detail/config.hpp>
#include <ocl/print.hpp>

namespace ocl
{
	enum struct return_type : int
	{
		invalid = 0,
		okay	= 100,
		err,
		count = err - okay + 1,
	};

	namespace detail
	{
		using option_error = std::runtime_error;

		inline void throw_option_invalid_type_error(const boost::string_view& loc = BOOST_CURRENT_LOCATION.to_string())
		{
			throw option_error(loc.to_string());
		}
	} // namespace detail

	class option final
	{
	public:
		option() = delete;
		explicit option(const return_type& return_type)
			: ret_(return_type)
		{
			if (ret_ == return_type::invalid)
				detail::throw_option_invalid_type_error();
		}

		~option() = default;

		option& operator=(const option&) = delete;
		option(const option&)			 = delete;

		option& expect(const char* input)
		{
			assert(ret_ != return_type::invalid);

			if (ret_ == return_type::err)
			{
				io::println(input ? input : "option::error");
                detail::throw_option_invalid_type_error();
			}

			return *this;
		}

		template <typename Handleable>
		option& expect(const char* input)
		{
			assert(ret_ != return_type::invalid);

			if (ret_ == return_type::err)
			{
				// AMLALE: Shall it be a functor or container here?
				Handleable{}(input ? input : "option::error");
			}

			return *this;
		}

	private:
		return_type ret_{return_type::invalid};
	};

	namespace detail
	{
		// AMLALE: The operator() are marked as `noexcept` as failing conditions within an evaluation (say a overloads operator==) proves that the
		// predictate is wrong. Thus program state is undefined.

		struct eq_teller final
		{
			template <class ObjFirst, class ObjLast>
			bool operator()(ObjFirst a, ObjLast b) noexcept
			{
				return (a == b);
			}
		};

		struct greater_than_teller final
		{
			template <class ObjFirst, class ObjLast>
			bool operator()(ObjFirst a, ObjLast b) noexcept
			{
				return (a > b);
			}
		};

		struct less_than_teller final
		{
			template <class ObjFirst, class ObjLast>
			bool operator()(ObjFirst a, ObjLast b) noexcept
			{
				return (a < b);
			}
		};
	} // namespace detail

	template <typename Teller, typename... Lst>
	inline return_type eval(const Teller& tell, Lst&&... arg)
	{
		return tell(std::forward<Lst>(arg)...) ? return_type::okay : return_type::err;
	}

	template <typename... Lst>
	inline return_type eval_less_than(Lst&&... arg)
	{
		return detail::less_than_teller{}(std::forward<Lst>(arg)...) ? return_type::okay : return_type::err;
	}

	template <typename... Lst>
	inline return_type eval_eq(Lst&&... arg)
	{
		return detail::eq_teller{}(std::forward<Lst>(arg)...) ? return_type::okay : return_type::err;
	}

	template <typename... Lst>
	inline return_type eval_greater_than(Lst&&... arg)
	{
		return detail::greater_than_teller{}(std::forward<Lst>(arg)...) ? return_type::okay : return_type::err;
	}

	inline return_type eval_true() noexcept
	{
		return return_type::okay;
	}

	inline return_type eval_false() noexcept
	{
		return return_type::err;
	}

	inline return_type eval_invalid() noexcept
	{
		return return_type::invalid;
	}
} // namespace ocl

#endif /* ifndef __OCL_CORE_OPTION */