aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--COPYING.md28
-rw-r--r--api/logic/CMakeLists.txt2
-rw-r--r--api/logic/minecraft/World.cpp192
-rw-r--r--api/logic/minecraft/World.h26
-rw-r--r--api/logic/minecraft/WorldList.cpp2
-rw-r--r--libraries/optional-bare/CMakeLists.txt5
-rw-r--r--libraries/optional-bare/LICENSE.txt23
-rw-r--r--libraries/optional-bare/README.md5
-rw-r--r--libraries/optional-bare/include/nonstd/optional508
10 files changed, 722 insertions, 70 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b178462e..b91da735 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -264,6 +264,7 @@ add_subdirectory(libraries/rainbow) # Qt extension for colors
add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
add_subdirectory(libraries/classparser) # google analytics library
+add_subdirectory(libraries/optional-bare)
############################### Built Artifacts ###############################
diff --git a/COPYING.md b/COPYING.md
index 70ff7ce2..db25ec01 100644
--- a/COPYING.md
+++ b/COPYING.md
@@ -223,3 +223,31 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+
+# optional-bare
+
+ Code from https://github.com/martinmoene/optional-bare/
+
+ Boost Software License - Version 1.0 - August 17th, 2003
+
+ Permission is hereby granted, free of charge, to any person or organization
+ obtaining a copy of the software and accompanying documentation covered by
+ this license (the "Software") to use, reproduce, display, distribute,
+ execute, and transmit the Software, and to prepare derivative works of the
+ Software, and to permit third-parties to whom the Software is furnished to
+ do so, all subject to the following:
+
+ The copyright notices in the Software and this entire statement, including
+ the above license grant, this restriction and the following disclaimer,
+ must be included in all copies of the Software, in whole or in part, and
+ all derivative works of the Software, unless such copies or derivative
+ works are solely in the form of machine-executable object code generated by
+ a source language processor.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt
index 15916bb5..be4318a8 100644
--- a/api/logic/CMakeLists.txt
+++ b/api/logic/CMakeLists.txt
@@ -526,7 +526,7 @@ set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISI
generate_export_header(MultiMC_logic)
# Link
-target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} BuildConfig)
+target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} optional-bare BuildConfig)
target_link_libraries(MultiMC_logic Qt5::Core Qt5::Xml Qt5::Network Qt5::Concurrent)
# Mark and export headers
diff --git a/api/logic/minecraft/World.cpp b/api/logic/minecraft/World.cpp
index 06a6080a..ad06bb83 100644
--- a/api/logic/minecraft/World.cpp
+++ b/api/logic/minecraft/World.cpp
@@ -32,7 +32,36 @@
#include <QCoreApplication>
-QString gameTypeToString(GameType type)
+#include <nonstd/optional>
+
+using nonstd::optional;
+using nonstd::nullopt;
+
+GameType::GameType(nonstd::optional<int> original):
+ original(original)
+{
+ if(!original) {
+ return;
+ }
+ switch(*original) {
+ case 0:
+ type = GameType::Survival;
+ break;
+ case 1:
+ type = GameType::Creative;
+ break;
+ case 2:
+ type = GameType::Adventure;
+ break;
+ case 3:
+ type = GameType::Spectator;
+ break;
+ default:
+ break;
+ }
+}
+
+QString GameType::toTranslatedString() const
{
switch (type)
{
@@ -47,7 +76,31 @@ QString gameTypeToString(GameType type)
default:
break;
}
- return QObject::tr("Unknown");
+ if(original) {
+ return QCoreApplication::translate("GameType", "Unknown (%1)").arg(*original);
+ }
+ return QCoreApplication::translate("GameType", "Undefined");
+}
+
+QString GameType::toLogString() const
+{
+ switch (type)
+ {
+ case GameType::Survival:
+ return "Survival";
+ case GameType::Creative:
+ return "Creative";
+ case GameType::Adventure:
+ return "Adventure";
+ case GameType::Spectator:
+ return "Spectator";
+ default:
+ break;
+ }
+ if(original) {
+ return QString("Unknown (%1)").arg(*original);
+ }
+ return "Undefined";
}
std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data)
@@ -58,15 +111,22 @@ std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data)
return nullptr;
}
std::istringstream foo(std::string(output.constData(), output.size()));
- auto pair = nbt::io::read_compound(foo);
+ try {
+ auto pair = nbt::io::read_compound(foo);
- if(pair.first != "")
- return nullptr;
+ if(pair.first != "")
+ return nullptr;
- if(pair.second == nullptr)
- return nullptr;
+ if(pair.second == nullptr)
+ return nullptr;
- return std::move(pair.second);
+ return std::move(pair.second);
+ }
+ catch (const nbt::io::input_error &e)
+ {
+ qWarning() << "Unable to parse level.dat:" << e.what();
+ return nullptr;
+ }
}
QByteArray serializeLevelDat(nbt::tag_compound * levelInfo)
@@ -288,14 +348,16 @@ bool World::rename(const QString &newName)
return true;
}
-static QString read_string (nbt::value& parent, const char * name, const QString & fallback = QString())
+namespace {
+
+optional<QString> read_string (nbt::value& parent, const char * name)
{
try
{
auto &namedValue = parent.at(name);
if(namedValue.get_type() != nbt::tag_type::String)
{
- return fallback;
+ return nullopt;
}
auto & tag_str = namedValue.as<nbt::tag_string>();
return QString::fromStdString(tag_str.get());
@@ -303,25 +365,25 @@ static QString read_string (nbt::value& parent, const char * name, const QString
catch (const std::out_of_range &e)
{
// fallback for old world formats
- qWarning() << "String NBT tag" << name << "could not be found. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "String NBT tag" << name << "could not be found.";
+ return nullopt;
}
catch (const std::bad_cast &e)
{
// type mismatch
- qWarning() << "NBT tag" << name << "could not be converted to string. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "NBT tag" << name << "could not be converted to string.";
+ return nullopt;
}
}
-static int64_t read_long (nbt::value& parent, const char * name, const int64_t & fallback = 0)
+optional<int64_t> read_long (nbt::value& parent, const char * name)
{
try
{
auto &namedValue = parent.at(name);
if(namedValue.get_type() != nbt::tag_type::Long)
{
- return fallback;
+ return nullopt;
}
auto & tag_str = namedValue.as<nbt::tag_long>();
return tag_str.get();
@@ -329,25 +391,25 @@ static int64_t read_long (nbt::value& parent, const char * name, const int64_t &
catch (const std::out_of_range &e)
{
// fallback for old world formats
- qWarning() << "Long NBT tag" << name << "could not be found. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "Long NBT tag" << name << "could not be found.";
+ return nullopt;
}
catch (const std::bad_cast &e)
{
// type mismatch
- qWarning() << "NBT tag" << name << "could not be converted to long. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "NBT tag" << name << "could not be converted to long.";
+ return nullopt;
}
}
-static int read_int (nbt::value& parent, const char * name, const int & fallback = 0)
+optional<int> read_int (nbt::value& parent, const char * name)
{
try
{
auto &namedValue = parent.at(name);
if(namedValue.get_type() != nbt::tag_type::Int)
{
- return fallback;
+ return nullopt;
}
auto & tag_str = namedValue.as<nbt::tag_int>();
return tag_str.get();
@@ -355,62 +417,72 @@ static int read_int (nbt::value& parent, const char * name, const int & fallback
catch (const std::out_of_range &e)
{
// fallback for old world formats
- qWarning() << "Int NBT tag" << name << "could not be found. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "Int NBT tag" << name << "could not be found.";
+ return nullopt;
}
catch (const std::bad_cast &e)
{
// type mismatch
- qWarning() << "NBT tag" << name << "could not be converted to int. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "NBT tag" << name << "could not be converted to int.";
+ return nullopt;
}
}
+GameType read_gametype(nbt::value& parent, const char * name) {
+ return GameType(read_int(parent, name));
+}
+
+}
+
void World::loadFromLevelDat(QByteArray data)
{
- try
+ auto levelData = parseLevelDat(data);
+ if(!levelData)
{
- auto levelData = parseLevelDat(data);
- if(!levelData)
- {
- is_valid = false;
- return;
- }
-
- auto &val = levelData->at("Data");
- is_valid = val.get_type() == nbt::tag_type::Compound;
- if(!is_valid)
- return;
+ is_valid = false;
+ return;
+ }
- m_actualName = read_string(val, "LevelName", m_folderName);
+ nbt::value * valPtr = nullptr;
+ try {
+ valPtr = &levelData->at("Data");
+ }
+ catch (const std::out_of_range &e) {
+ qWarning() << "Unable to read NBT tags from " << m_folderName << ":" << e.what();
+ is_valid = false;
+ return;
+ }
+ nbt::value &val = *valPtr;
+ is_valid = val.get_type() == nbt::tag_type::Compound;
+ if(!is_valid)
+ return;
- int64_t temp = read_long(val, "LastPlayed", 0);
- if(temp == 0)
- {
- m_lastPlayed = levelDatTime;
- }
- else
- {
- m_lastPlayed = QDateTime::fromMSecsSinceEpoch(temp);
- }
+ auto name = read_string(val, "LevelName");
+ m_actualName = name ? *name : m_folderName;
- int GameType_val = read_int(val, "GameType", 0);
- m_gameType = (GameType) GameType_val;
+ auto timestamp = read_long(val, "LastPlayed");
+ m_lastPlayed = timestamp ? QDateTime::fromMSecsSinceEpoch(*timestamp) : levelDatTime;
- m_randomSeed = read_long(val, "RandomSeed", 0);
+ m_gameType = read_gametype(val, "GameType");
- qDebug() << "World Name:" << m_actualName;
- qDebug() << "Last Played:" << m_lastPlayed.toString();
- qDebug() << "Seed:" << m_randomSeed;
- qDebug() << "GameMode:" << GameType_val;
+ optional<int64_t> randomSeed;
+ try {
+ auto &WorldGen_val = val.at("WorldGenSettings");
+ randomSeed = read_long(WorldGen_val, "seed");
}
- catch (const nbt::io::input_error &e)
- {
- qWarning() << "Unable to load" << m_folderName << ":" << e.what();
- is_valid = false;
- return;
+ catch (std::out_of_range) {}
+ if(!randomSeed) {
+ randomSeed = read_long(val, "RandomSeed");
+ }
+ m_randomSeed = randomSeed ? *randomSeed : 0;
+
+ qDebug() << "World Name:" << m_actualName;
+ qDebug() << "Last Played:" << m_lastPlayed.toString();
+ if(randomSeed) {
+ qDebug() << "Seed:" << *randomSeed;
}
+ qDebug() << "GameType:" << m_gameType.toLogString();
}
bool World::replace(World &with)
diff --git a/api/logic/minecraft/World.h b/api/logic/minecraft/World.h
index d04c1040..ba7c357c 100644
--- a/api/logic/minecraft/World.h
+++ b/api/logic/minecraft/World.h
@@ -16,17 +16,27 @@
#pragma once
#include <QFileInfo>
#include <QDateTime>
+#include <nonstd/optional>
#include "multimc_logic_export.h"
-enum class GameType
-{
- Survival,
- Creative,
- Adventure,
- Spectator
+struct MULTIMC_LOGIC_EXPORT GameType {
+ GameType() = default;
+ GameType (nonstd::optional<int> original);
+
+ QString toTranslatedString() const;
+ QString toLogString() const;
+
+ enum
+ {
+ Unknown = -1,
+ Survival = 0,
+ Creative,
+ Adventure,
+ Spectator
+ } type = Unknown;
+ nonstd::optional<int> original;
};
-QString MULTIMC_LOGIC_EXPORT gameTypeToString(GameType type);
class MULTIMC_LOGIC_EXPORT World
{
@@ -98,6 +108,6 @@ protected:
QDateTime levelDatTime;
QDateTime m_lastPlayed;
int64_t m_randomSeed = 0;
- GameType m_gameType = GameType::Survival;
+ GameType m_gameType;
bool is_valid = false;
};
diff --git a/api/logic/minecraft/WorldList.cpp b/api/logic/minecraft/WorldList.cpp
index 94b59da4..7bb9ab76 100644
--- a/api/logic/minecraft/WorldList.cpp
+++ b/api/logic/minecraft/WorldList.cpp
@@ -175,7 +175,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
return world.name();
case GameModeColumn:
- return gameTypeToString(world.gameType());
+ return world.gameType().toTranslatedString();
case LastPlayedColumn:
return world.lastPlayed();
diff --git a/libraries/optional-bare/CMakeLists.txt b/libraries/optional-bare/CMakeLists.txt
new file mode 100644
index 00000000..b8b498c5
--- /dev/null
+++ b/libraries/optional-bare/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.1)
+project(optional-bare)
+
+add_library(optional-bare INTERFACE)
+target_include_directories(optional-bare INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
diff --git a/libraries/optional-bare/LICENSE.txt b/libraries/optional-bare/LICENSE.txt
new file mode 100644
index 00000000..36b7cd93
--- /dev/null
+++ b/libraries/optional-bare/LICENSE.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/libraries/optional-bare/README.md b/libraries/optional-bare/README.md
new file mode 100644
index 00000000..e29ff7c1
--- /dev/null
+++ b/libraries/optional-bare/README.md
@@ -0,0 +1,5 @@
+# optional bare
+
+A simple single-file header-only version of a C++17-like optional for default-constructible, copyable types, for C++98 and later.
+
+Imported from: https://github.com/martinmoene/optional-bare/commit/0bb1d183bcee1e854c4ea196b533252c51f98b81
diff --git a/libraries/optional-bare/include/nonstd/optional b/libraries/optional-bare/include/nonstd/optional
new file mode 100644
index 00000000..ecbfa030
--- /dev/null
+++ b/libraries/optional-bare/include/nonstd/optional
@@ -0,0 +1,508 @@
+//
+// Copyright 2017-2019 by Martin Moene
+//
+// https://github.com/martinmoene/optional-bare
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef NONSTD_OPTIONAL_BARE_HPP
+#define NONSTD_OPTIONAL_BARE_HPP
+
+#define optional_bare_MAJOR 1
+#define optional_bare_MINOR 1
+#define optional_bare_PATCH 0
+
+#define optional_bare_VERSION optional_STRINGIFY(optional_bare_MAJOR) "." optional_STRINGIFY(optional_bare_MINOR) "." optional_STRINGIFY(optional_bare_PATCH)
+
+#define optional_STRINGIFY( x ) optional_STRINGIFY_( x )
+#define optional_STRINGIFY_( x ) #x
+
+// optional-bare configuration:
+
+#define optional_OPTIONAL_DEFAULT 0
+#define optional_OPTIONAL_NONSTD 1
+#define optional_OPTIONAL_STD 2
+
+#if !defined( optional_CONFIG_SELECT_OPTIONAL )
+# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD )
+#endif
+
+// Control presence of exception handling (try and auto discover):
+
+#ifndef optional_CONFIG_NO_EXCEPTIONS
+# if _MSC_VER
+# include <cstddef> // for _HAS_EXCEPTIONS
+# endif
+# if _MSC_VER
+# include <cstddef> // for _HAS_EXCEPTIONS
+# endif
+# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
+# define optional_CONFIG_NO_EXCEPTIONS 0
+# else
+# define optional_CONFIG_NO_EXCEPTIONS 1
+# endif
+#endif
+
+// C++ language version detection (C++20 is speculative):
+// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
+
+#ifndef optional_CPLUSPLUS
+# if defined(_MSVC_LANG ) && !defined(__clang__)
+# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
+# else
+# define optional_CPLUSPLUS __cplusplus
+# endif
+#endif
+
+#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L )
+#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L )
+#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L )
+#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L )
+#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L )
+
+// C++ language version (represent 98 as 3):
+
+#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) )
+
+// Use C++17 std::optional if available and requested:
+
+#if optional_CPP17_OR_GREATER && defined(__has_include )
+# if __has_include( <optional> )
+# define optional_HAVE_STD_OPTIONAL 1
+# else
+# define optional_HAVE_STD_OPTIONAL 0
+# endif
+#else
+# define optional_HAVE_STD_OPTIONAL 0
+#endif
+
+#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) )
+
+//
+// Using std::optional:
+//
+
+#if optional_USES_STD_OPTIONAL
+
+#include <optional>
+#include <utility>
+
+namespace nonstd {
+
+ using std::in_place;
+ using std::in_place_type;
+ using std::in_place_index;
+ using std::in_place_t;
+ using std::in_place_type_t;
+ using std::in_place_index_t;
+
+ using std::optional;
+ using std::bad_optional_access;
+ using std::hash;
+
+ using std::nullopt;
+ using std::nullopt_t;
+
+ using std::operator==;
+ using std::operator!=;
+ using std::operator<;
+ using std::operator<=;
+ using std::operator>;
+ using std::operator>=;
+ using std::make_optional;
+ using std::swap;
+}
+
+#else // optional_USES_STD_OPTIONAL
+
+#include <cassert>
+
+#if ! optional_CONFIG_NO_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+namespace nonstd { namespace optional_bare {
+
+// type for nullopt
+
+struct nullopt_t
+{
+ struct init{};
+ nullopt_t( init ) {}
+};
+
+// extra parenthesis to prevent the most vexing parse:
+
+const nullopt_t nullopt(( nullopt_t::init() ));
+
+// optional access error.
+
+#if ! optional_CONFIG_NO_EXCEPTIONS
+
+class bad_optional_access : public std::logic_error
+{
+public:
+ explicit bad_optional_access()
+ : logic_error( "bad optional access" ) {}
+};
+
+#endif // optional_CONFIG_NO_EXCEPTIONS
+
+// Simplistic optional: requires T to be default constructible, copyable.
+
+template< typename T >
+class optional
+{
+private:
+ typedef void (optional::*safe_bool)() const;
+
+public:
+ typedef T value_type;
+
+ optional()
+ : has_value_( false )
+ {}
+
+ optional( nullopt_t )
+ : has_value_( false )
+ {}
+
+ optional( T const & arg )
+ : has_value_( true )
+ , value_ ( arg )
+ {}
+
+ template< class U >
+ optional( optional<U> const & other )
+ : has_value_( other.has_value() )
+ , value_ ( other.value() )
+ {}
+
+ optional & operator=( nullopt_t )
+ {
+ reset();
+ return *this;
+ }
+
+ template< class U >
+ optional & operator=( optional<U> const & other )
+ {
+ has_value_ = other.has_value();
+ value_ = other.value();
+ return *this;
+ }
+
+ void swap( optional & rhs )
+ {
+ using std::swap;
+ if ( has_value() == true && rhs.has_value() == true ) { swap( **this, *rhs ); }
+ else if ( has_value() == false && rhs.has_value() == true ) { initialize( *rhs ); rhs.reset(); }
+ else if ( has_value() == true && rhs.has_value() == false ) { rhs.initialize( **this ); reset(); }
+ }
+
+ // observers
+
+ value_type const * operator->() const
+ {
+ return assert( has_value() ),
+ &value_;
+ }
+
+ value_type * operator->()
+ {
+ return assert( has_value() ),
+ &value_;
+ }
+
+ value_type const & operator*() const
+ {
+ return assert( has_value() ),
+ value_;
+ }
+
+ value_type & operator*()
+ {
+ return assert( has_value() ),
+ value_;
+ }
+
+#if optional_CPP11_OR_GREATER
+ explicit operator bool() const
+ {
+ return has_value();
+ }
+#else
+ operator safe_bool() const
+ {
+ return has_value() ? &optional::this_type_does_not_support_comparisons : 0;
+ }
+#endif
+
+ bool has_value() const
+ {
+ return has_value_;
+ }
+
+ value_type const & value() const
+ {
+#if optional_CONFIG_NO_EXCEPTIONS
+ assert( has_value() );
+#else
+ if ( ! has_value() )
+ throw bad_optional_access();
+#endif
+ return value_;
+ }
+
+ value_type & value()
+ {
+#if optional_CONFIG_NO_EXCEPTIONS
+ assert( has_value() );
+#else
+ if ( ! has_value() )
+ throw bad_optional_access();
+#endif
+ return value_;
+ }
+
+ template< class U >
+ value_type value_or( U const & v ) const
+ {
+ return has_value() ? value() : static_cast<value_type>( v );
+ }
+
+ // modifiers
+
+ void reset()
+ {
+ has_value_ = false;
+ }
+
+private:
+ void this_type_does_not_support_comparisons() const {}
+
+ template< typename V >
+ void initialize( V const & value )
+ {
+ assert( ! has_value() );
+ value_ = value;
+ has_value_ = true;
+ }
+
+private:
+ bool has_value_;
+ value_type value_;
+};
+
+// Relational operators
+
+template< typename T, typename U >
+inline bool operator==( optional<T> const & x, optional<U> const & y )
+{
+ return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y;
+}
+
+template< typename T, typename U >
+inline bool operator!=( optional<T> const & x, optional<U> const & y )
+{
+ return !(x == y);
+}
+
+template< typename T, typename U >
+inline bool operator<( optional<T> const & x, optional<U> const & y )
+{
+ return (!y) ? false : (!x) ? true : *x < *y;
+}
+
+template< typename T, typename U >
+inline bool operator>( optional<T> const & x, optional<U> const & y )
+{
+ return (y < x);
+}
+
+template< typename T, typename U >
+inline bool operator<=( optional<T> const & x, optional<U> const & y )
+{
+ return !(y < x);
+}
+
+template< typename T, typename U >
+inline bool operator>=( optional<T> const & x, optional<U> const & y )
+{
+ return !(x < y);
+}
+
+// Comparison with nullopt
+
+template< typename T >
+inline bool operator==( optional<T> const & x, nullopt_t )
+{
+ return (!x);
+}
+
+template< typename T >
+inline bool operator==( nullopt_t, optional<T> const & x )
+{
+ return (!x);
+}
+
+template< typename T >
+inline bool operator!=( optional<T> const & x, nullopt_t )
+{
+ return bool(x);
+}
+
+template< typename T >
+inline bool operator!=( nullopt_t, optional<T> const & x )
+{
+ return bool(x);
+}
+
+template< typename T >
+inline bool operator<( optional<T> const &, nullopt_t )
+{
+ return false;
+}
+
+template< typename T >
+inline bool operator<( nullopt_t, optional<T> const & x )
+{
+ return bool(x);
+}
+
+template< typename T >
+inline bool operator<=( optional<T> const & x, nullopt_t )
+{
+ return (!x);
+}
+
+template< typename T >
+inline bool operator<=( nullopt_t, optional<T> const & )
+{
+ return true;
+}
+
+template< typename T >
+inline bool operator>( optional<T> const & x, nullopt_t )
+{
+ return bool(x);
+}
+
+template< typename T >
+inline bool operator>( nullopt_t, optional<T> const & )
+{
+ return false;
+}
+
+template< typename T >
+inline bool operator>=( optional<T> const &, nullopt_t )
+{
+ return true;
+}
+
+template< typename T >
+inline bool operator>=( nullopt_t, optional<T> const & x )
+{
+ return (!x);
+}
+
+// Comparison with T
+
+template< typename T, typename U >
+inline bool operator==( optional<T> const & x, U const & v )
+{
+ return bool(x) ? *x == v : false;
+}
+
+template< typename T, typename U >
+inline bool operator==( U const & v, optional<T> const & x )
+{
+ return bool(x) ? v == *x : false;
+}
+
+template< typename T, typename U >
+inline bool operator!=( optional<T> const & x, U const & v )
+{
+ return bool(x) ? *x != v : true;
+}
+
+template< typename T, typename U >
+inline bool operator!=( U const & v, optional<T> const & x )
+{
+ return bool(x) ? v != *x : true;
+}
+
+template< typename T, typename U >
+inline bool operator<( optional<T> const & x, U const & v )
+{
+ return bool(x) ? *x < v : true;
+}
+
+template< typename T, typename U >
+inline bool operator<( U const & v, optional<T> const & x )
+{
+ return bool(x) ? v < *x : false;
+}
+
+template< typename T, typename U >
+inline bool operator<=( optional<T> const & x, U const & v )
+{
+ return bool(x) ? *x <= v : true;
+}
+
+template< typename T, typename U >
+inline bool operator<=( U const & v, optional<T> const & x )
+{
+ return bool(x) ? v <= *x : false;
+}
+
+template< typename T, typename U >
+inline bool operator>( optional<T> const & x, U const & v )
+{
+ return bool(x) ? *x > v : false;
+}
+
+template< typename T, typename U >
+inline bool operator>( U const & v, optional<T> const & x )
+{
+ return bool(x) ? v > *x : true;
+}
+
+template< typename T, typename U >
+inline bool operator>=( optional<T> const & x, U const & v )
+{
+ return bool(x) ? *x >= v : false;
+}
+
+template< typename T, typename U >
+inline bool operator>=( U const & v, optional<T> const & x )
+{
+ return bool(x) ? v >= *x : true;
+}
+
+// Specialized algorithms
+
+template< typename T >
+void swap( optional<T> & x, optional<T> & y )
+{
+ x.swap( y );
+}
+
+// Convenience function to create an optional.
+
+template< typename T >
+inline optional<T> make_optional( T const & v )
+{
+ return optional<T>( v );
+}
+
+} // namespace optional-bare
+
+using namespace optional_bare;
+
+} // namespace nonstd
+
+#endif // optional_USES_STD_OPTIONAL
+
+#endif // NONSTD_OPTIONAL_BARE_HPP