Nasal String wrapper and allow adding methods to string objects.

- Add nasal::String for wrapping Nasal string data and accessing
   string methods (which eg. could be exposed to Nasal)
 - Allow adding functions from C/C++ which are callable on
   Nasal strings.
This commit is contained in:
Thomas Geymayer 2013-01-23 01:09:57 +01:00
parent 53b9fd2110
commit e7f9486aa1
9 changed files with 334 additions and 3 deletions

View File

@ -441,14 +441,17 @@ static const char* getMember_r(naContext ctx, naRef obj, naRef field, naRef* out
naRef p;
struct VecRec* pv;
if(--count < 0) return "too many parents";
if(!IS_HASH(obj) && !IS_GHOST(obj)) return "non-objects have no members";
if (IS_GHOST(obj)) {
if (ghostGetMember(ctx, obj, field, out)) return "";
if(!ghostGetMember(ctx, obj, globals->parentsRef, &p)) return 0;
} else {
} else if (IS_HASH(obj)) {
if(naHash_get(obj, field, out)) return "";
if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
} else if (IS_STR(obj) ) {
return getMember_r(ctx, getStringMethods(ctx), field, out, count);
} else {
return "non-objects have no members";
}
if(!IS_VEC(p)) return "object \"parents\" field not vector";

View File

@ -3,6 +3,7 @@ include (SimGearComponent)
set(HEADERS
Ghost.hxx
NasalHash.hxx
NasalString.hxx
from_nasal_detail.hxx
from_nasal.hxx
nasal_traits.hxx
@ -11,6 +12,7 @@ set(HEADERS
set(SOURCES
NasalHash.cxx
NasalString.cxx
from_nasal.cxx
to_nasal.cxx
)

View File

@ -0,0 +1,180 @@
// Wrapper class for Nasal strings
//
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "NasalString.hxx"
#include "to_nasal.hxx"
#include <algorithm>
#include <cassert>
#include <cstring>
#include <functional>
#include <stdexcept>
namespace nasal
{
/**
* Predicate (eg. for std::find_if) returning true if no character of the
* stored string given by the range [begin, end) matches.
*/
struct no_match:
public std::unary_function<const char, bool>
{
no_match(const char* begin, const char* end):
_begin(begin),
_end(end)
{}
bool operator()(const char c) const
{
return std::find(_begin, _end, c) == _end;
}
private:
const char* _begin;
const char* _end;
};
//template<typename Iterator>
//Iterator
//rfind_first_of( Iterator rbegin_src, Iterator rend_src,
// Iterator begin_find, Iterator end_find )
//{
// for(; rbegin_src != rend_src; --rbegin_src)
// {
// for(Iterator chr = begin_find; chr != end_find; ++chr)
// {
// if( *rbegin_src == *chr )
// return rbegin_src;
// }
// }
// return rend_src;
//}
const size_t String::npos = static_cast<size_t>(-1);
//----------------------------------------------------------------------------
String::String(naContext c, const char* str):
_str( to_nasal(c, str) )
{
assert( naIsString(_str) );
}
//----------------------------------------------------------------------------
String::String(naRef str):
_str(str)
{
assert( naIsString(_str) );
}
//----------------------------------------------------------------------------
const char* String::c_str() const
{
return naStr_data(_str);
}
//----------------------------------------------------------------------------
const char* String::begin() const
{
return c_str();
}
//----------------------------------------------------------------------------
const char* String::end() const
{
return c_str() + size();
}
//----------------------------------------------------------------------------
size_t String::size() const
{
return naStr_len(_str);
}
//----------------------------------------------------------------------------
size_t String::length() const
{
return size();
}
//----------------------------------------------------------------------------
bool String::empty() const
{
return size() == 0;
}
//----------------------------------------------------------------------------
int String::compare(size_t pos, size_t len, const String& rhs) const
{
if( pos >= size() )
throw std::out_of_range("nasal::String::compare: pos");
return memcmp( begin() + pos,
rhs.begin(),
std::min(rhs.size(), std::min(size() - pos, len)) );
}
//----------------------------------------------------------------------------
bool String::starts_with(const String& rhs) const
{
return rhs.size() <= size() && compare(0, npos, rhs) == 0;
}
//----------------------------------------------------------------------------
size_t String::find(const char c, size_t pos) const
{
if( pos >= size() )
return npos;
const char* result = std::find(begin() + pos, end(), c);
return result != end() ? result - begin() : npos;
}
//----------------------------------------------------------------------------
size_t String::find_first_of(const String& chr, size_t pos) const
{
if( pos >= size() )
return npos;
const char* result = std::find_first_of( begin() + pos, end(),
chr.begin(), chr.end() );
return result != end() ? result - begin() : npos;
}
//----------------------------------------------------------------------------
size_t String::find_first_not_of(const String& chr, size_t pos) const
{
if( pos >= size() )
return npos;
const char* result = std::find_if( begin() + pos, end(),
no_match(chr.begin(), chr.end()) );
return result != end() ? result - begin() : npos;
}
//----------------------------------------------------------------------------
const naRef String::get_naRef() const
{
return _str;
}
} // namespace nasal

View File

@ -0,0 +1,80 @@
///@file Wrapper class for Nasal strings
//
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef SG_NASAL_STRING_HXX_
#define SG_NASAL_STRING_HXX_
#include "from_nasal.hxx"
#include "to_nasal.hxx"
namespace nasal
{
/**
* A Nasal String
*/
class String
{
public:
static const size_t npos;
/**
* Create a new Nasal String
*
* @param c Nasal context for creating the string
* @param str String data
*/
String(naContext c, const char* str);
/**
* Initialize from an existing Nasal String
*
* @param str Existing Nasal String
*/
String(naRef string);
const char* c_str() const;
const char* begin() const;
const char* end() const;
size_t size() const;
size_t length() const;
bool empty() const;
int compare(size_t pos, size_t len, const String& rhs) const;
bool starts_with(const String& rhs) const;
size_t find(const char c, size_t pos = 0) const;
size_t find_first_of(const String& chr, size_t pos = 0) const;
size_t find_first_not_of(const String& chr, size_t pos = 0) const;
/**
* Get Nasal representation of String
*/
const naRef get_naRef() const;
protected:
naRef _str;
};
} // namespace nasal
#endif /* SG_NASAL_STRING_HXX_ */

View File

@ -2,6 +2,7 @@
#include "Ghost.hxx"
#include "NasalHash.hxx"
#include "NasalString.hxx"
#include <boost/shared_ptr.hpp>
@ -111,6 +112,27 @@ int main(int argc, char* argv[])
Hash mod = hash.createHash("mod");
mod.set("parent", hash);
String string( to_nasal(c, "Test") );
VERIFY( from_nasal<std::string>(c, string.get_naRef()) == "Test" );
VERIFY( string.c_str() == std::string("Test") );
VERIFY( string.starts_with(string) );
VERIFY( string.starts_with(String(c, "T")) );
VERIFY( string.starts_with(String(c, "Te")) );
VERIFY( string.starts_with(String(c, "Tes")) );
VERIFY( string.starts_with(String(c, "Test")) );
VERIFY( !string.starts_with(String(c, "Test1")) );
VERIFY( !string.starts_with(String(c, "bb")) );
VERIFY( !string.starts_with(String(c, "bbasdasdafasd")) );
VERIFY( string.find('e') == 1 );
VERIFY( string.find('9') == String::npos );
VERIFY( string.find_first_of(String(c, "st")) == 2 );
VERIFY( string.find_first_of(String(c, "st"), 3) == 3 );
VERIFY( string.find_first_of(String(c, "xyz")) == String::npos );
VERIFY( string.find_first_not_of(String(c, "Tst")) == 1 );
VERIFY( string.find_first_not_of(String(c, "Tse"), 2) == 3 );
VERIFY( string.find_first_not_of(String(c, "abc")) == 0 );
VERIFY( string.find_first_not_of(String(c, "abc"), 20) == String::npos );
Ghost<BasePtr>::init("BasePtr")
.method<&Base::member>("member")
.member("str", &Base::getString, &Base::setString);

View File

@ -18,6 +18,7 @@
#include "from_nasal_detail.hxx"
#include "NasalHash.hxx"
#include "NasalString.hxx"
#include <simgear/misc/sg_path.hxx>
@ -70,4 +71,13 @@ namespace nasal
return Hash(ref, c);
}
//----------------------------------------------------------------------------
String from_nasal_helper(naContext c, naRef ref, String*)
{
if( !naIsString(ref) )
throw bad_nasal_cast("Not a string");
return String(ref);
}
} // namespace nasal

View File

@ -36,6 +36,7 @@ class SGPath;
namespace nasal
{
class Hash;
class String;
/**
* Thrown when converting a type from/to Nasal has failed
@ -87,6 +88,11 @@ namespace nasal
*/
Hash from_nasal_helper(naContext c, naRef ref, Hash*);
/**
* Convert a Nasal string to a nasal::String
*/
String from_nasal_helper(naContext c, naRef ref, String*);
/**
* Convert a Nasal number to a C++ numeric type
*/

View File

@ -119,6 +119,9 @@ naRef naInit_readline(naContext c);
naRef naInit_gtk(naContext ctx);
naRef naInit_cairo(naContext ctx);
// Returns a hash which can be used to add methods callable on strings
naRef naInit_string(naContext c);
// Context stack inspection, frame zero is the "top"
int naStackDepth(naContext ctx);
int naGetLine(naContext ctx, int frame);
@ -159,6 +162,7 @@ naRef naStr_fromdata(naRef dst, const char* data, int len);
naRef naStr_concat(naRef dest, naRef s1, naRef s2);
naRef naStr_substr(naRef dest, naRef str, int start, int len);
naRef naInternSymbol(naRef sym);
naRef getStringMethods(naContext c);
// Vector utilities:
int naVec_size(naRef v);

View File

@ -320,3 +320,27 @@ static int fromnum(double val, unsigned char* s)
*ptr = 0;
return ptr - s;
}
//------------------------------------------------------------------------------
static naRef string_methods;
static int init = 0; // As we can't use naNil() for static initialization we
// need a separate variable for saving whether we have
// already initialized.
//------------------------------------------------------------------------------
naRef naInit_string(naContext c)
{
string_methods = naNewHash(c);
init = 1;
return string_methods;
}
//------------------------------------------------------------------------------
naRef getStringMethods(naContext c)
{
if( !init )
return naNil();
return string_methods;
}