/******************************************************************************\
* LuaValue.hpp *
* A class that somewhat mimics a Lua value. *
* *
* *
* Copyright (C) 2005-2013 by Leandro Motta Barros. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy *
* of this software and associated documentation files (the "Software"), to *
* deal in the Software without restriction, including without limitation the *
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or *
* sell copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* 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. *
\******************************************************************************/
#ifndef _DILUCULUM_LUA_VALUE_HPP_
#define _DILUCULUM_LUA_VALUE_HPP_
#include <lua.hpp>
#include <map>
#include <stdexcept>
#include <string>
#include <Diluculum/CppObject.hpp>
#include <Diluculum/LuaUserData.hpp>
#include <Diluculum/LuaFunction.hpp>
#include <Diluculum/Types.hpp>
namespace Diluculum
{
/** A class that somewhat mimics a Lua value. Notice that a \c LuaValue is
* a C++-side thing. There is absolutely no relationship between a
* \c LuaValue and a Lua state. This is particularly important for tables
* and userdata: in Lua, these things are garbage-collectible objects, and
* variables are just references to them. In Diluculum, a \c LuaValue
* represents the value (hence the name!). So, if a \c LuaValue holds a
* table, then it contains a collection of keys and values. Similarly, if it
* holds a userdata, it actually contains a block of memory with some data.
*/
class LuaValue
{
public:
/// Constructs a \c LuaValue with a \c nil value.
LuaValue();
/// Constructs a \c LuaValue with boolean type and \c b value.
LuaValue (bool b);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (float n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (double n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (long double n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (short n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (unsigned short n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (int n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (unsigned n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (long n);
/// Constructs a \c LuaValue with number type and \c n value.
LuaValue (unsigned long n);
/// Constructs a \c LuaValue with string type and \c s value.
LuaValue (const std::string& s);
/// Constructs a \c LuaValue with string type and \c s value.
LuaValue (const char* s);
/// Constructs a \c LuaValue with table type and \c t value.
LuaValue (const LuaValueMap& t);
/// Constructs a \c LuaValue with function type and \c f value.
LuaValue (lua_CFunction f);
/// Constructs a \c LuaValue with function type and \c f value.
LuaValue (const LuaFunction& f);
/// Constructs a \c LuaValue with "user data" type and \c ud value.
LuaValue (const LuaUserData& ud);
/** Constructs a \c LuaValue from a \c LuaValueList. The first value on
* the list is used to initialize the \c LuaValue. If the
* \c LuaValueList is empty, initializes the constructed \c LuaValue
* to \c Nil.
*/
LuaValue (const LuaValueList& v);
/// Copy constructor.
LuaValue (const LuaValue& other);
/// Destroys the \c LuaValue, freeing all the resources owned by it.
~LuaValue() { destroyObjectAtData(); }
/// Assignment operator.
LuaValue& operator= (const LuaValue& rhs);
/** Assigns a \c LuaValueList to a \c LuaValue. The first value on
* the list is used to initialize the \c LuaValue. If the
* \c LuaValueList is empty, sets the \c LuaValue to \c Nil.
*/
const LuaValueList& operator= (const LuaValueList& rhs);
/** Returns one of the <tt>LUA_T*</tt> constants from <tt>lua.h</tt>,
* representing the type stored in this \c LuaValue.
*/
int type() const { return dataType_; }
/** Returns the type of this \c LuaValue as a string, just like the Lua
* built-in function \c type().
* @return One of the following strings: <tt>"nil"</tt>,
* <tt>"boolean"</tt>, <tt>"number"</tt>, <tt>"string"</tt>,
* <tt>"table"</tt>, <tt>"function"</tt>, <tt>"userdata"</tt>.
*/
std::string typeName() const;
/** Return the value as a number.
* @throw TypeMismatchError If the value is not a number (this is a
* strict check; no type conversion is performed).
*/
lua_Number asNumber() const;
/** Return the value as an integer.
* @throw TypeMismatchError If the value is not a number (this is a
* strict check; no type conversion is performed -- no other
* than the conversion from \c lua_Number to \c lua_Integer,
* that is).
*/
lua_Integer asInteger() const;
/** Return the value as a string.
* @throw TypeMismatchError If the value is not a string (this is a
* strict check; no type conversion is performed).
*/
const std::string& asString() const;
/** Return the value as a boolean.
* @throw TypeMismatchError If the value is not a boolean (this is a
* strict check; no type conversion is performed).
*/
bool asBoolean() const;
/** Returns the value as a table (\c LuaValueMap).
* @note Notice that the table is returned by value. You may strongly
* consider using the subscript operator (that returns a
* reference) for accessing the values stored in a table-typed
* \c LuaValue.
* @throw TypeMismatchError If the value is not a table (this is a
* strict check; no type conversion is performed).
*/
LuaValueMap asTable() const;
/** Return the value as a \c const Lua function.
* @throw TypeMismatchError If the value is not a Lua function.
* (this is a strict check; no type conversion is performed).
*/
const LuaFunction& asFunction() const;
/** Return the value as a \c const (full) user data.
* @throw TypeMismatchError If the value is not a (full) user data
* (this is a strict check; no type conversion is performed).
*/
const LuaUserData& asUserData() const;
/** Return the value as a (full) user data.
* @note Since this is returned as a non-\c const reference, the
* \c LuaUserData::getData() method can be used to get
* read/write access to the raw user data.
* @throw TypeMismatchError If the value is not a (full) user data
* (this is a strict check; no type conversion is performed).
*/
LuaUserData& asUserData();
/** Assuming that the value stores a C++ object exported to or
* instantiated in Lua, returns a pointer to the (\c const) C++
* object.
*/
template<class T>
T asObjectPtr() const
{
return static_cast<T>(
static_cast<const Impl::CppObject*>(asUserData().getData())->ptr);
}
/** Assuming that the value stores a C++ object exported to or
* instantiated in Lua, returns a pointer to the C++ object.
*/
template<class T>
T asObjectPtr()
{
return static_cast<T>(
static_cast<Impl::CppObject*>(asUserData().getData())->ptr);
}
/** "Less than" operator for <tt>LuaValue</tt>s.
* @return The order relationship is quite arbitrary for
* <tt>LuaValue</tt>s, but this has to be defined in order to
* \c LuaValueMap work nicely. Anyway, here are the rules used
* to determine who is less than who:
* - First, \c typeName() is called for both
* <tt>LuaValue</tt>s and they are compared with the usual
* "less than" operator for strings.
* - If both type names are equal, but something different
* than <tt>"nil"</tt> and <tt>"table"</tt>, then the values
* contained in the <tt>LuaValue</tt>s are compared using
* the "less than" operator for that type.
* - If both type names are <tt>"nil"</tt>, the function
* returns \c false.
* - If both type names are <tt>"table"</tt>, then the number
* of elements in each table are compared. The shorter table
* is "less than" the larger table.
* - If both tables have the same size, then each entry is
* recursively compared (that is, using the rules described
* here). For each entry, the key is compared first, than
* the value. This is done until finding something "less
* than" the other thing.
* - If no differences are found, \c false is obviously
* returned.
*/
bool operator< (const LuaValue& rhs) const;
/** "Greater than" operator for <tt>LuaValue</tt>s.
* @return The rules for determining who is greater than who are
* similar to the ones described in \c operator<.
*/
bool operator> (const LuaValue& rhs) const;
/** "Equal" operator for <tt>LuaValue</tt>s.
* @return \c true if <tt>*this</tt> and \c rhs have the same value.
* \c false otherwise.
*/
bool operator== (const LuaValue& rhs) const;
/** "Different" operator for <tt>LuaValue</tt>s.
* @return \c true if <tt>*this</tt> and \c rhs don't have the same
* value. \c false otherwise.
*/
bool operator!= (const LuaValue& rhs) const
{ return !(*this == rhs); }
/** Returns a reference to a field of this \c LuaValue (assuming it is
* a table). If there is no value associated with the key passed as
* parameter, inserts a new value (\c nil) and returns a reference to
* it.
* @throw TypeMismatchError If this \c LuaValue does not hold a table.
*/
LuaValue& operator[] (const LuaValue& key);
/** Returns a \c const reference to a field of this \c LuaValue
* (assuming it is a table). If there is no value associated with the
* key passed as parameter, returns \c Nil.
* @throw TypeMismatchError If this \c LuaValue does not hold a table.
*/
const LuaValue& operator[] (const LuaValue& key) const;
private:
/** Destroys the object allocated at the \c data_ member, freeing its
* resources.
*/
void destroyObjectAtData();
/// This is used to allow the \c data_ member to store multiple types.
union PossibleTypes
{
lua_Number typeNumber;
std::string typeString;
bool typeBool;
LuaValueMap typeLuaValueMap;
LuaFunction typeFunction;
LuaUserData typeUserData;
PossibleTypes() {}
~PossibleTypes() {}
// introduced because of gcc8 memcpy warnings
PossibleTypes& operator= (const PossibleTypes& rhs)
{
typeNumber = rhs.typeNumber;
// typeString = rhs.typeString;
typeBool = rhs.typeBool;
// typeLuaValueMap = rhs.typeLuaValueMap;
// typeFunction = rhs.typeFunction;
// typeUserData = rhs.typeUserData;
return *this;
}
};
/** This stores the actual data of this \c LuaValue.
* <p>Implementation details: The values are allocated here using
* placement new, with destructors explicitly called whenever
* necessary.
*/
PossibleTypes data_;
/** The actual type stored in this \c LuaValue. The values here are the
* type constants defined by Lua, like \c LUA_TNUMBER and \c LUA_TNIL.
*/
int dataType_;
};
/// A constant with the value of \c nil.
const LuaValue Nil;
/// A constant that is an empty \c LuaValueMap.
const LuaValueMap EmptyLuaValueMap;
/// A constant with value of an empty table.
const LuaValue EmptyTable (EmptyLuaValueMap);
} // namespace Diluculum
#endif // _DILUCULUM_LUA_VALUE_HPP_