]> git.mxchange.org Git - simgear.git/commitdiff
Nasal String wrapper and allow adding methods to string objects.
authorThomas Geymayer <tomgey@gmail.com>
Wed, 23 Jan 2013 00:09:57 +0000 (01:09 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Thu, 31 Jan 2013 18:07:33 +0000 (19:07 +0100)
 - 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.

simgear/nasal/code.c
simgear/nasal/cppbind/CMakeLists.txt
simgear/nasal/cppbind/NasalString.cxx [new file with mode: 0644]
simgear/nasal/cppbind/NasalString.hxx [new file with mode: 0644]
simgear/nasal/cppbind/cppbind_test.cxx
simgear/nasal/cppbind/from_nasal.cxx
simgear/nasal/cppbind/from_nasal_detail.hxx
simgear/nasal/nasal.h
simgear/nasal/string.c

index 08d710f81f6014edce893b2d13b8a3fce9f85ff3..511f490f51b2c3b776b5dbb7f9bf9752f89ed410 100644 (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";
index 636116eb8d919356e6307fb23fc58446eb6d3b42..62df00587b5fe51efa3a3d731d2931e9972d7a7e 100644 (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
 )
diff --git a/simgear/nasal/cppbind/NasalString.cxx b/simgear/nasal/cppbind/NasalString.cxx
new file mode 100644 (file)
index 0000000..41388b3
--- /dev/null
@@ -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
diff --git a/simgear/nasal/cppbind/NasalString.hxx b/simgear/nasal/cppbind/NasalString.hxx
new file mode 100644 (file)
index 0000000..d30dfeb
--- /dev/null
@@ -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_ */
index 416d4a0ec21bb50f165b15a2d913bf9d2ee68e45..422f3d70205d3aab137de8f7dc1e8842a6058181 100644 (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);
index 0c3fba95cf8c24c145fdb029388fd039a6fed7d7..2eb1e1f428ffe9fa5624930aaadb1a3c362b9274 100644 (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
index aeec6e207952b65bde02837a076ac2b8467b928e..7eb0c966b5a6c10c0e288446241bc3322621cbd3 100644 (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
    */
index bf48cdc209463e34bbbb997de0f8164d4efc9659..7fc54203a7e8c550c1014b436ad0d6d3b83b49a5 100644 (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);
index 4855054cddd24cc1983eb0d373056c64c7b66bf3..ce8b5ac252721919a91293196b8ba29b277d1604 100644 (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;
+}