GH-3229 fix copy seed button not working for newer worlds

Added the `optional-bare` library and refactored NBT reading
code to support this change.
This commit is contained in:
Petr Mrázek 2021-02-06 15:58:03 +01:00
parent f8ca96a335
commit 1868e0ccf1
10 changed files with 728 additions and 76 deletions

View File

@ -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 ###############################

View File

@ -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.

View File

@ -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

View File

@ -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 != "")
if(pair.first != "")
return nullptr;
if(pair.second == nullptr)
return nullptr;
return std::move(pair.second);
}
catch (const nbt::io::input_error &e)
{
qWarning() << "Unable to parse level.dat:" << e.what();
return nullptr;
if(pair.second == nullptr)
return nullptr;
return std::move(pair.second);
}
}
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;
m_actualName = read_string(val, "LevelName", m_folderName);
int64_t temp = read_long(val, "LastPlayed", 0);
if(temp == 0)
{
m_lastPlayed = levelDatTime;
}
else
{
m_lastPlayed = QDateTime::fromMSecsSinceEpoch(temp);
}
int GameType_val = read_int(val, "GameType", 0);
m_gameType = (GameType) GameType_val;
m_randomSeed = read_long(val, "RandomSeed", 0);
qDebug() << "World Name:" << m_actualName;
qDebug() << "Last Played:" << m_lastPlayed.toString();
qDebug() << "Seed:" << m_randomSeed;
qDebug() << "GameMode:" << GameType_val;
}
catch (const nbt::io::input_error &e)
{
qWarning() << "Unable to load" << m_folderName << ":" << e.what();
is_valid = false;
return;
}
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;
auto name = read_string(val, "LevelName");
m_actualName = name ? *name : m_folderName;
auto timestamp = read_long(val, "LastPlayed");
m_lastPlayed = timestamp ? QDateTime::fromMSecsSinceEpoch(*timestamp) : levelDatTime;
m_gameType = read_gametype(val, "GameType");
optional<int64_t> randomSeed;
try {
auto &WorldGen_val = val.at("WorldGenSettings");
randomSeed = read_long(WorldGen_val, "seed");
}
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)

View File

@ -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;
};

View File

@ -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();

View File

@ -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")

View File

@ -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.

View File

@ -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

View File

@ -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