From 1deafa3ad1644cee66602b4bb5499e0de8f4480a Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sun, 8 Jan 2017 20:17:10 -0500 Subject: [PATCH] add c++17 optional --- Makefile | 2 +- expression.cpp | 8 ++- expression.h | 4 +- optional.h | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 optional.h diff --git a/Makefile b/Makefile index 937a589..ec82e73 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ LINK.o = $(LINK.cc) -CXXFLAGS = -std=c++11 -g -Wall +CXXFLAGS = -std=c++14 -g -Wall CCFLAGS = -g DUMP_OBJS = dumpobj.o disassembler.o zrdz_disassembler.o diff --git a/expression.cpp b/expression.cpp index abb1c58..801ae4f 100644 --- a/expression.cpp +++ b/expression.cpp @@ -145,9 +145,7 @@ bool simplify_expression(expression &e) { * if force is true, treat OP_LOC records as OP_VAL (for omf) */ -// should return std::optional... - -uint32_t evaluate_expression(expression &e, bool force) { +optional evaluate_expression(expression &e, bool force) { std::vector tmp; for (const auto &t : e.stack) { if (t.tag == OP_LOC && force) { @@ -163,7 +161,7 @@ uint32_t evaluate_expression(expression &e, bool force) { } } - if (tmp.size() == 1 && tmp.front().tag == OP_VAL) return tmp.front().value; - return 0; + if (tmp.size() == 1 && tmp.front().tag == OP_VAL) return optional(tmp.front().value); + return optional(); } diff --git a/expression.h b/expression.h index db3c56d..0047681 100644 --- a/expression.h +++ b/expression.h @@ -4,6 +4,8 @@ #include #include +#include "optional.h" + struct expr { expr(int t = 0, uint32_t v = 0, uint32_t s = 0) : tag(t), value(v), section(s) @@ -25,7 +27,7 @@ struct expression { }; -uint32_t evaluate_expression(expression &e, bool force = false); +optional evaluate_expression(expression &e, bool force = false); bool simplify_expression(expression &e); diff --git a/optional.h b/optional.h new file mode 100644 index 0000000..b38ca32 --- /dev/null +++ b/optional.h @@ -0,0 +1,139 @@ +#ifndef __optional_h__ +#define __optional_h__ + +#include +#include + +class bad_optional_access : public std::exception { +public: + virtual const char* what() const noexcept { + return "bad optional access"; + } +}; + +template +class optional { +public: + typedef T value_type; + + optional() = default; + + optional( const optional& other ) { + if (other._engaged) { + new (std::addressof(_data)) T(*other); + _engaged = true; + } + } + + optional( const optional&& other ) { + if (other._engaged) { + new (std::addressof(_data)) T(std::move(*other)); + _engaged = true; + } + } + + template < class U > + optional( const optional& other ) { + if (other._engaged) { + new (std::addressof(_data)) T(*other); + _engaged = true; + } + } + + template < class U > + optional( optional&& other ) { + if (other._engaged) { + new (std::addressof(_data)) T(std::move(*other)); + _engaged = true; + } + } + + + template + optional(U &&value) { + new(std::addressof(_data)) T(std::forward(value)); + _engaged = true; + } + + + + ~optional() { + reset(); + } + + + constexpr explicit operator bool() const { + return _engaged; + } + + constexpr bool has_value() const { + return _engaged; + } + + /* these should throw ... */ + constexpr T& value() & { + if (!_engaged) throw bad_optional_access(); + return *reinterpret_cast(std::addressof(_data)); + } + + constexpr const T & value() const & { + if (!_engaged) throw bad_optional_access(); + return *reinterpret_cast(std::addressof(_data)); + } + + constexpr T&& value() && { + if (!_engaged) throw bad_optional_access(); + return *reinterpret_cast(std::addressof(_data)); + } + + constexpr const T&& value() const && { + if (!_engaged) throw bad_optional_access(); + return *reinterpret_cast(std::addressof(_data)); + } + + + template< class U > + constexpr T value_or( U&& default_value ) const& { + return bool(*this) ? **this : static_cast(std::forward(default_value)); + } + + template< class U > + constexpr T value_or( U&& default_value ) && { + return bool(*this) ? std::move(**this) : static_cast(std::forward(default_value)); + } + + constexpr const T* operator->() const { + return reinterpret_cast(std::addressof(_data)); + } + constexpr T* operator->() { + return reinterpret_cast(std::addressof(_data)); + } + + constexpr const T& operator*() const& { + return *reinterpret_cast(std::addressof(_data)); + } + constexpr T& operator*() & { + return *reinterpret_cast(std::addressof(_data)); + } + constexpr const T&& operator*() const&& { + return *reinterpret_cast(std::addressof(_data)); + } + constexpr T&& operator*() && { + return *reinterpret_cast(std::addressof(_data)); + } + + + void reset() { + if (_engaged) { + reinterpret_cast(std::addressof(_data))->~T(); + _engaged = false; + } + } + +private: + bool _engaged = false; + typename std::aligned_storage::type _data; +}; + +#endif +