added string-pooling for shader variable names and entity keys
authorspog <spog>
Sun, 26 Feb 2006 22:27:38 +0000 (22:27 +0000)
committerspog <spog>
Sun, 26 Feb 2006 22:27:38 +0000 (22:27 +0000)
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@26 8a3a26a2-13c4-0310-b231-cf6edde360e5

27 files changed:
include/ientity.h
libs/container/hashfunc.h
libs/container/hashtable.h
libs/convert.h
libs/entitylib.h
libs/fs_filesystem.h
libs/generic/arrayrange.h
libs/generic/constant.h
libs/generic/static.h
libs/gtkutil/dialog.cpp
libs/libs.vcproj
libs/stream/textstream.h
libs/string/string.h
libs/uniquenames.h
plugins/entity/entity.cpp
plugins/entity/modelskinkey.h
plugins/mapq3/plugin.cpp
plugins/md3model/model.h
plugins/shaders/shaders.cpp
radiant/commands.cpp
radiant/dialog.cpp
radiant/eclass_def.cpp
radiant/eclass_doom3.cpp
radiant/main.cpp
radiant/map.cpp
radiant/texwindow.cpp
radiant/xywindow.cpp

index ac10c1a..34a5638 100644 (file)
@@ -111,6 +111,8 @@ public:
   virtual bool getShowNames() = 0;
   virtual void setShowAngles(bool showAngles) = 0;
   virtual bool getShowAngles() = 0;
+
+  virtual void printStatistics() const = 0;
 };
 
 #include "modulesystem.h"
index 03e5e26..a4ec5fe 100644 (file)
@@ -320,6 +320,15 @@ inline hash_t string_hash_nocase(const char* string, hash_t previous = 0)
   return hash_ub1_nocase(reinterpret_cast<const ub1*>(string), string_length(string), previous);
 }
 
+struct RawStringHash
+{
+  typedef hash_t hash_type;
+  hash_type operator()(const char* string) const
+  {
+    return string_hash(string);
+  }
+};
+
 struct HashString
 {
   typedef hash_t hash_type;
index c38739a..c4b1ade 100644 (file)
@@ -166,11 +166,11 @@ namespace HashTableDetail
       increment();
       return tmp;
     }
-    value_type& operator*()
+    value_type& operator*() const
     {
       return m_node->m_value;
     }
-    value_type* operator->()
+    value_type* operator->() const
     {
       return &(operator*());
     }
index ea7a71f..f7f4f99 100644 (file)
@@ -248,7 +248,7 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
     return ostream << convert.m_range;
   }
 
-  for(const char* p = convert.m_range.begin; p != convert.m_range.end;)
+  for(const char* p = convert.m_range.first; p != convert.m_range.last;)
   {
     if(!char_is_ascii(*p))
     {
@@ -286,7 +286,7 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
     return ostream << convert.m_range;
   }
 
-  for(const char* p = convert.m_range.begin; p != convert.m_range.end; ++p)
+  for(const char* p = convert.m_range.first; p != convert.m_range.last; ++p)
   {
     if(!char_is_ascii(*p))
     {
index 5c477c6..b9e9300 100644 (file)
@@ -34,7 +34,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "math/vector.h"
 #include "math/aabb.h"
 #include "undolib.h"
-#include "string/string.h"
+#include "string/pooledstring.h"
 #include "generic/referencecounted.h"
 #include "scenelib.h"
 #include "container/container.h"
@@ -421,14 +421,21 @@ public:
     virtual void erase(const char* key, Value& value) = 0;
   };
 
+  static StringPool& getPool()
+  {
+    return Static<StringPool, KeyContext>::instance();
+  }
 private:
   static EntityCreator::KeyValueChangedFunc m_entityKeyValueChanged;
   static Counter* m_counter;
 
   EntityClass* m_eclass;
 
+  class KeyContext{};
+  typedef Static<StringPool, KeyContext> KeyPool;
+  typedef PooledString<KeyPool> Key;
   typedef SmartPointer<KeyValue> KeyValuePtr;
-  typedef UnsortedMap<CopiedString, KeyValuePtr > KeyValues;
+  typedef UnsortedMap<Key, KeyValuePtr> KeyValues;
   KeyValues m_keyValues;
 
   typedef UnsortedSet<Observer*> Observers;
@@ -504,7 +511,7 @@ private:
       (*i).second->instanceDetach(m_undo.map());
     }
 
-    CopiedString key((*i).first);
+    Key key((*i).first);
     KeyValuePtr value((*i).second);
     m_keyValues.erase(i);
     notifyErase(key.c_str(), *value);
index 653d60d..0c22a4b 100644 (file)
@@ -57,8 +57,8 @@ class GenericFileSystem
       : m_path(path), m_depth(path_get_depth(c_str()))
     {
     }
-    Path(const char* start, const char* finish)
-      : m_path(start, finish), m_depth(path_get_depth(c_str()))
+    Path(StringRange range)
+      : m_path(range), m_depth(path_get_depth(c_str()))
     {
     }
     bool operator<(const Path& other) const
@@ -121,7 +121,7 @@ public:
       const char* end = path_remove_directory(path.c_str());
       while(end[0] != '\0')
       {
-        Path dir(path.c_str(), end);
+        Path dir(StringRange(path.c_str(), end));
         m_entries.insert(value_type(dir, Entry(0)));
         end = path_remove_directory(end);
       }
index 7bb3188..a05489a 100644 (file)
@@ -29,36 +29,36 @@ template<typename Element>
 struct ArrayRange
 {
   typedef Element* Iterator;
-  ArrayRange(Iterator _begin, Iterator _end)
-    : begin(_begin), end(_end)
+  ArrayRange(Iterator first, Iterator last)
+    : first(first), last(last)
   {
   }
-  Iterator begin;
-  Iterator end;
+  Iterator first;
+  Iterator last;
 };
 
 template<typename Element>
-inline ArrayRange<Element> makeArrayRange(Element* begin, Element* end)
+inline ArrayRange<Element> makeArrayRange(Element* first, Element* last)
 {
-  return ArrayRange<Element>(begin, end);
+  return ArrayRange<Element>(first, last);
 }
 
 template<typename Element>
 struct ArrayConstRange
 {
   typedef const Element* Iterator;
-  ArrayConstRange(Iterator _begin, Iterator _end)
-    : begin(_begin), end(_end)
+  ArrayConstRange(Iterator first, Iterator last)
+    : first(first), last(last)
   {
   }
-  Iterator begin;
-  Iterator end;
+  Iterator first;
+  Iterator last;
 };
 
 template<typename Element>
-inline ArrayConstRange<Element> makeArrayRange(const Element* begin, const Element* end)
+inline ArrayConstRange<Element> makeArrayRange(const Element* first, const Element* last)
 {
-  return ArrayConstRange<Element>(begin, end);
+  return ArrayConstRange<Element>(first, last);
 }
 
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
@@ -69,4 +69,6 @@ inline ArrayConstRange<Element> makeArrayRange(const Element* begin, const Eleme
 typedef ArrayConstRange<const char*> StringArrayRange;
 #define STRING_ARRAY_RANGE(array) (StringArrayRange(array, ARRAY_END(array)))
 
+typedef ArrayRange<const char> StringRange;
+
 #endif
index 0c2f1b5..42b2fa5 100644 (file)
@@ -45,4 +45,6 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
 #define STRING_CONSTANT(name, value) TYPE_CONSTANT(name, value, const char*)
 #define INTEGER_CONSTANT(name, value) TYPE_CONSTANT(name, value, int)
 
+STRING_CONSTANT(EmptyString, "");
+
 #endif
index 50fb3b7..8169182 100644 (file)
@@ -27,14 +27,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include <cstddef>
 
+class Null
+{
+};
+
 /// \brief A singleton which is statically initialised.
 ///
 /// \param Type The singleton object type.
+/// \param Type The type distinguishing this instance from others of the same type.
 ///
 /// \dontinclude generic/static.cpp
 /// \skipline Static example
 /// \until end example
-template<typename Type>
+template<typename Type, typename Context = Null>
 class Static
 {
   static Type m_instance;
@@ -45,19 +50,20 @@ public:
   }
 };
 
-template<typename Type>
-Type Static<Type>::m_instance;
+template<typename Type, typename Context>
+Type Static<Type, Context>::m_instance;
 
 
 /// \brief A singleton which is lazily initialised.
 /// The instance is constructed the first time it is referenced, and is never destroyed.
 ///
 /// \param Type The singleton object type.
+/// \param Type The type distinguishing this instance from others of the same type.
 ///
 /// \dontinclude generic/static.cpp
 /// \skipline LazyStatic example
 /// \until end example
-template<typename Type>
+template<typename Type, typename Context = Null>
 class LazyStatic
 {
   static Type* m_instance; // this will be initialised to 0 by the CRT, according to the c++ standard
@@ -72,8 +78,8 @@ public:
   }
 };
 
-template<typename Type>
-Type* LazyStatic<Type>::m_instance;
+template<typename Type, typename Context>
+Type* LazyStatic<Type, Context>::m_instance;
 
 
 /// \brief A singleton which keeps a count of the number of times it is referenced.
@@ -82,7 +88,8 @@ Type* LazyStatic<Type>::m_instance;
 /// Use with SmartStatic.
 ///
 /// \param Type The singleton object type.
-template<typename Type>
+/// \param Type The type distinguishing this instance from others of the same type.
+template<typename Type, typename Context = Null>
 class CountedStatic
 {
   static std::size_t m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
@@ -108,34 +115,35 @@ public:
   }
 };
 
-template<typename Type>
-std::size_t CountedStatic<Type>::m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
-template<typename Type>
-Type* CountedStatic<Type>::m_instance;
+template<typename Type, typename Context>
+std::size_t CountedStatic<Type, Context>::m_refcount; // this will be initialised to 0 by the CRT, according to the c++ standard
+template<typename Type, typename Context>
+Type* CountedStatic<Type, Context>::m_instance;
 
 /// \brief A reference to a CountedStatic.
 /// Guarantees that CountedStatic<Type> will be constructed for the lifetime of this object.
 ///
 /// \param Type The type parameter of the CountedStatic to reference.
+/// \param Type The type distinguishing this instance from others of the same type.
 ///
 /// \dontinclude generic/static.cpp
 /// \skipline SmartStatic example
 /// \until end example
-template<typename Type>
+template<typename Type, typename Context = Null>
 class SmartStatic
 {
 public:
   SmartStatic()
   {
-    CountedStatic<Type>::capture();
+    CountedStatic<Type, Context>::capture();
   }
   ~SmartStatic()
   {
-    CountedStatic<Type>::release();
+    CountedStatic<Type, Context>::release();
   }
   Type& instance()
   {
-    return CountedStatic<Type>::instance();
+    return CountedStatic<Type, Context>::instance();
   }
 };
 
index 0529178..0f95e9a 100644 (file)
@@ -209,7 +209,7 @@ RadioHBox RadioHBox_new(StringArrayRange names)
 
   GSList* group = 0;
   GtkRadioButton* radio = 0;
-  for(StringArrayRange::Iterator i = names.begin; i != names.end; ++i)
+  for(StringArrayRange::Iterator i = names.first; i != names.last; ++i)
   {
     radio = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label(group, *i));
     gtk_widget_show(GTK_WIDGET(radio));
index 56f067f..c418b70 100644 (file)
                        Name="string"
                        Filter="">
                        <File
+                               RelativePath=".\string\pooledstring.cpp">
+                       </File>
+                       <File
+                               RelativePath=".\string\pooledstring.h">
+                       </File>
+                       <File
                                RelativePath=".\string\string.cpp">
                        </File>
                        <File
index 96fc7a6..8e0c72c 100644 (file)
@@ -302,13 +302,11 @@ inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const
 }
 
 
-typedef ArrayRange<const char> StringRange;
-
 /// \brief Writes a \p range of characters to \p ostream.
 template<typename TextOutputStreamType>
 inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const StringRange& range)
 {
-  ostream.write(range.begin, range.end - range.begin);
+  ostream.write(range.first, range.last - range.first);
   return ostream;
 }
 
index cf6c064..9e0bcb0 100644 (file)
@@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <algorithm>
 
 #include "memory/allocator.h"
+#include "generic/arrayrange.h"
 
 /// \brief Returns true if \p string length is zero.
 /// O(1)
@@ -191,10 +192,10 @@ inline char* string_clone(const char* other, Allocator& allocator)
 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last), using \p allocator.
 /// The returned buffer must be released with \c string_release using a matching \p allocator.
 template<typename Allocator>
-inline char* string_clone_range(const char* first, const char* last, Allocator& allocator)
+inline char* string_clone_range(StringRange range, Allocator& allocator)
 {
-  std::size_t length = last - first;
-  char* copied = strncpy(string_new(length, allocator), first, length);
+  std::size_t length = range.last - range.first;
+  char* copied = strncpy(string_new(length, allocator), range.first, length);
   copied[length] = '\0';
   return copied;
 }
@@ -224,10 +225,10 @@ inline char* string_clone(const char* other)
 
 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last).
 /// The returned buffer must be released with \c string_release.
-inline char* string_clone_range(const char* first, const char* last)
+inline char* string_clone_range(StringRange range)
 {
   DefaultAllocator<char> allocator;
-  return string_clone_range(first, last, allocator);
+  return string_clone_range(range, allocator);
 }
 
 typedef char* char_pointer;
@@ -343,8 +344,8 @@ public:
     : Buffer(string)
   {
   }
-  String(const char* first, const char* last)
-    : Buffer(first, last)
+  String(StringRange range)
+    : Buffer(range)
   {
   }
 
@@ -360,6 +361,12 @@ public:
     temp.swap(*this);
     return *this;
   }
+  String& operator=(StringRange range)
+  {
+    String temp(range);
+    temp.swap(*this);
+    return *this;
+  }
 
   void swap(String& other)
   {
@@ -426,9 +433,9 @@ class CopiedBuffer : private Allocator
 {
   char* m_string;
 
-  char* copy_range(const char* first, const char* last)
+  char* copy_range(StringRange range)
   {
-    return string_clone_range(first, last, static_cast<Allocator&>(*this));
+    return string_clone_range(range, static_cast<Allocator&>(*this));
   }
   char* copy(const char* other)
   {
@@ -461,8 +468,8 @@ public:
     : Allocator(allocator), m_string(copy(string))
   {
   }
-  CopiedBuffer(const char* first, const char* last, const Allocator& allocator = Allocator())
-    : Allocator(allocator), m_string(copy_range(first, last))
+  CopiedBuffer(StringRange range, const Allocator& allocator = Allocator())
+    : Allocator(allocator), m_string(copy_range(range))
   {
   }
   const char* c_str() const
@@ -485,11 +492,11 @@ class SmartBuffer : private Allocator
 {
   char* m_buffer;
 
-  char* copy_range(const char* first, const char* last)
+  char* copy_range(StringRange range)
   {
-    char* buffer = Allocator::allocate(sizeof(std::size_t) + (last - first) + 1);
-    strncpy(buffer + sizeof(std::size_t), first, last - first);
-    buffer[sizeof(std::size_t) + (last - first)] = '\0';
+    char* buffer = Allocator::allocate(sizeof(std::size_t) + (range.last - range.first) + 1);
+    strncpy(buffer + sizeof(std::size_t), range.first, range.last - range.first);
+    buffer[sizeof(std::size_t) + (range.last - range.first)] = '\0';
     *reinterpret_cast<std::size_t*>(buffer) = 0;
     return buffer;
   }
@@ -541,8 +548,8 @@ public:
   {
     incref(m_buffer);
   }
-  SmartBuffer(const char* first, const char* last, const Allocator& allocator = Allocator())
-    : Allocator(allocator), m_buffer(copy_range(first, last))
+  SmartBuffer(StringRange range, const Allocator& allocator = Allocator())
+    : Allocator(allocator), m_buffer(copy_range(range))
   {
     incref(m_buffer);
   }
index 4c4a531..868336d 100644 (file)
@@ -130,7 +130,7 @@ inline name_t name_read(const char* name)
     end = p;
   }
 
-  return name_t(CopiedString(name, end), Postfix(end));
+  return name_t(CopiedString(StringRange(name, end)), Postfix(end));
 }
 
 
index 06f9173..5866934 100644 (file)
@@ -258,6 +258,11 @@ public:
   {
     return g_showAngles;
   }
+
+  void printStatistics() const
+  {
+    StringPool_analyse(EntityKeyValues::getPool());
+  }
 };
 
 Quake3EntityCreator g_Quake3EntityCreator;
index 6c02a8e..58c7da2 100644 (file)
@@ -34,7 +34,7 @@ inline void parseTextureName(CopiedString& name, const char* token)
 {
   StringOutputStream cleaned(256);
   cleaned << PathCleaned(token);
-  name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
+  name = StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
 }
 
 class ModelSkinKey : public ModuleObserver
index 8fa7532..8e031ed 100644 (file)
@@ -500,11 +500,11 @@ public:
   typedef Value* const_iterator;
   const_iterator begin() const
   {
-    return m_children.begin;
+    return m_children.first;
   }
   const_iterator end() const
   {
-    return m_children.end;
+    return m_children.last;
   }
 };
 
index 0aca555..1b41e16 100644 (file)
@@ -75,7 +75,7 @@ inline void parseTextureName(CopiedString& name, const char* token)
 {
   StringOutputStream cleaned(256);
   cleaned << PathCleaned(token);
-  name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
+  name = StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
 }
 
 // generic renderable triangle surface
index 7732681..3a7fae2 100644 (file)
@@ -51,7 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <glib/gslist.h>
 
 #include "debugging/debugging.h"
-#include "string/string.h"
+#include "string/pooledstring.h"
 #include "math/vector.h"
 #include "generic/callback.h"
 #include "generic/referencecounted.h"
@@ -225,21 +225,29 @@ Image* loadSpecial(void* environment, const char* name)
   return GlobalTexturesCache().loadImage(name);
 }
 
-
+class ShaderPoolContext
+{
+};
+typedef Static<StringPool, ShaderPoolContext> ShaderPool;
+typedef PooledString<ShaderPool> ShaderString;
+typedef ShaderString ShaderVariable;
+typedef ShaderString ShaderValue;
+typedef CopiedString TextureExpression;
 
 // clean a texture name to the qtexture_t name format we use internally
 // NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case
 // information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name,
 // we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive.
 //++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present
-void parseTextureName(CopiedString& name, const char* token)
+template<typename StringType>
+void parseTextureName(StringType& name, const char* token)
 {
   StringOutputStream cleaned(256);
   cleaned << PathCleaned(token);
-  name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
+  name = CopiedString(StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str()))).c_str(); // remove extension
 }
 
-bool Tokeniser_parseTextureName(Tokeniser& tokeniser, CopiedString& name)
+bool Tokeniser_parseTextureName(Tokeniser& tokeniser, TextureExpression& name)
 {
   const char* token = tokeniser.getToken();
   if(token == 0)
@@ -251,13 +259,6 @@ bool Tokeniser_parseTextureName(Tokeniser& tokeniser, CopiedString& name)
   return true;
 }
 
-void parseShaderName(CopiedString& name, const char* token)
-{
-  StringOutputStream cleaned(256);
-  cleaned << PathCleaned(token);
-  name = cleaned.c_str();
-}
-
 bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
 {
   const char* token = tokeniser.getToken();
@@ -266,11 +267,11 @@ bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
     Tokeniser_unexpectedError(tokeniser, token, "#shader-name");
     return false;
   }
-  parseShaderName(name, token);
+  parseTextureName(name, token);
   return true;
 }
 
-bool Tokeniser_parseString(Tokeniser& tokeniser, CopiedString& string)
+bool Tokeniser_parseString(Tokeniser& tokeniser, ShaderString& string)
 {
   const char* token = tokeniser.getToken();
   if(token == 0)
@@ -284,12 +285,10 @@ bool Tokeniser_parseString(Tokeniser& tokeniser, CopiedString& string)
 
 
 
-typedef std::list<CopiedString> ShaderParameters;
-typedef std::list<CopiedString> ShaderArguments;
+typedef std::list<ShaderVariable> ShaderParameters;
+typedef std::list<ShaderVariable> ShaderArguments;
 
-typedef CopiedString TextureExpression;
-typedef CopiedString ShaderValue;
-typedef std::pair<CopiedString, CopiedString> BlendFuncExpression;
+typedef std::pair<ShaderVariable, ShaderVariable> BlendFuncExpression;
 
 class ShaderTemplate
 {
@@ -406,7 +405,7 @@ public:
 };
 
 
-bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
+bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, TextureExpression& bump, ShaderValue& heightmapScale)
 {
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
@@ -416,20 +415,20 @@ bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, CopiedString& bump, Copied
   return true;
 }
 
-bool Doom3Shader_parseAddnormals(Tokeniser& tokeniser, CopiedString& bump)
+bool Doom3Shader_parseAddnormals(Tokeniser& tokeniser, TextureExpression& bump)
 {
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ","));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "heightmap"));
-  CopiedString heightmapName;
-  CopiedString heightmapScale;
+  TextureExpression heightmapName;
+  ShaderValue heightmapScale;
   RETURN_FALSE_IF_FAIL(Doom3Shader_parseHeightmap(tokeniser, heightmapName, heightmapScale));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
   return true;
 }
 
-bool Doom3Shader_parseBumpmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
+bool Doom3Shader_parseBumpmap(Tokeniser& tokeniser, TextureExpression& bump, ShaderValue& heightmapScale)
 {
   const char* token = tokeniser.getToken();
   if(token == 0)
@@ -465,7 +464,7 @@ class LayerTemplate
 {
 public:
   LayerTypeId m_type;
-  CopiedString m_texture;
+  TextureExpression m_texture;
   BlendFuncExpression m_blendFunc;
   bool m_clampToBorder;
   ShaderValue m_alphaTest;
@@ -741,9 +740,9 @@ bool ShaderTemplate::parseDoom3(Tokeniser& tokeniser)
         if(string_equal_nocase(lightFalloffImage, "makeintensity"))
         {
           RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
-          CopiedString name;
+          TextureExpression name;
           RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
-          m_lightFalloffImage = name.c_str();
+          m_lightFalloffImage = name;
           RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
         }
         else
@@ -797,7 +796,7 @@ ShaderDefinitionMap g_shaderDefinitions;
 bool parseTemplateInstance(Tokeniser& tokeniser, const char* filename)
 {
   CopiedString name;
-  RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
+  RETURN_FALSE_IF_FAIL(Tokeniser_parseShaderName(tokeniser, name));
   const char* templateName = tokeniser.getToken();
   ShaderTemplate* shaderTemplate = findTemplate(templateName);
   if(shaderTemplate == 0)
@@ -1312,7 +1311,7 @@ void FreeShaders()
 bool ShaderTemplate::parseQuake3(Tokeniser& tokeniser)
 {
   // name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before)
-  m_textureName = m_Name;
+  m_textureName = m_Name.c_str();
 
   tokeniser.nextLine();
 
@@ -1486,7 +1485,7 @@ class Layer
 {
 public:
   LayerTypeId m_type;
-  CopiedString m_texture;
+  TextureExpression m_texture;
   BlendFunc m_blendFunc;
   bool m_clampToBorder;
   float m_alphaTest;
@@ -1924,6 +1923,8 @@ void Shaders_Load()
       lst = lst->next;
     }
   }
+
+  //StringPool_analyse(ShaderPool::instance());
 }
 
 void Shaders_Free()
index e873b6a..3015414 100644 (file)
@@ -486,7 +486,7 @@ public:
       }
       else // special key
       {
-        CopiedString keyName(value, keyEnd);
+        CopiedString keyName(StringRange(value, keyEnd));
         accelerator.key = global_keys_find(keyName.c_str());
         if(accelerator.key != 0)
         {
index f413f12..e57dae7 100644 (file)
@@ -558,7 +558,7 @@ void Dialog::addCombo(GtkWidget* vbox, const char* name, StringArrayRange values
   {
     GtkWidget* combo = gtk_combo_box_new_text();
 
-    for(StringArrayRange::Iterator i = values.begin; i != values.end; ++i)
+    for(StringArrayRange::Iterator i = values.first; i != values.last; ++i)
     {
       gtk_combo_box_append_text(GTK_COMBO_BOX(combo), *i);
     }
@@ -640,7 +640,7 @@ void Dialog::addRadio(GtkWidget* vbox, const char* name, int& data, StringArrayR
 
 void Dialog::addRadioIcons(GtkWidget* vbox, const char* name, StringArrayRange icons, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
 {
-  GtkWidget* table = gtk_table_new (2, static_cast<guint>(icons.end - icons.begin), FALSE);
+  GtkWidget* table = gtk_table_new (2, static_cast<guint>(icons.last - icons.first), FALSE);
   gtk_widget_show (table);
 
   gtk_table_set_row_spacings (GTK_TABLE (table), 5);
@@ -648,9 +648,9 @@ void Dialog::addRadioIcons(GtkWidget* vbox, const char* name, StringArrayRange i
 
   GSList* group = 0;
   GtkWidget* radio = 0;
-  for(StringArrayRange::Iterator icon = icons.begin; icon != icons.end; ++icon)
+  for(StringArrayRange::Iterator icon = icons.first; icon != icons.last; ++icon)
   {
-    guint pos = static_cast<guint>(icon - icons.begin);
+    guint pos = static_cast<guint>(icon - icons.first);
     GtkImage* image = new_local_image(*icon);
     gtk_widget_show(GTK_WIDGET(image));
     gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(image), pos, pos+1, 0, 1,
index 266968a..01341ed 100644 (file)
@@ -182,7 +182,7 @@ void setSpecialLoad(EntityClass *e, const char* pWhat, CopiedString& p)
   where = strchr(pText,'\"');
   if (where)
   {
-    p = CopiedString(pText, where);
+    p = StringRange(pText, where);
   }
   else
   {
index 56e84d6..966590f 100644 (file)
@@ -313,7 +313,7 @@ void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
     const char* key = tokeniser.getToken();
     
     const char* last = string_findFirstSpaceOrTab(key);
-    CopiedString first(key, last);
+    CopiedString first(StringRange(key, last));
 
     if(!string_empty(last))
     {
index 7668fb4..c9a5083 100644 (file)
@@ -619,3 +619,4 @@ int main (int argc, char* argv[])
 
   return EXIT_SUCCESS;
 }
+
index f4a23c1..c846ca7 100644 (file)
@@ -1046,6 +1046,8 @@ void Map_LoadFile (const char *filename)
   
   globalOutputStream() << makeLeftJustified(Unsigned(g_brushCount.get()), 5) << " primitive\n";
   globalOutputStream() << makeLeftJustified(Unsigned(g_entityCount.get()), 5) << " entities\n";
+
+  //GlobalEntityCreator().printStatistics();
   
   //
   // move the view to a start position
index 2e5c0fb..5828525 100644 (file)
@@ -159,9 +159,9 @@ void texturegroup_activated(GtkWidget* widget, gpointer data)
   reinterpret_cast<TextureGroupLoader*>(data)->loadGroup();
 }
 
-bool string_equal_start(const char* string, const char* start)
+bool string_equal_start(const char* string, StringRange start)
 {
-  return string_equal_n(string, start, string_length(start));
+  return string_equal_n(string, start.first, start.last - start.first);
 }
 
 GtkMenuItem* MenuItem_create(const char* name)
@@ -210,7 +210,7 @@ void TextureGroupsMenu_Construct(GtkMenu* menu, const TextureGroups& groups)
   {
     const char* dirName = (*i).c_str();
     const char* firstUnderscore = strchr(dirName, '_');
-    CopiedString dirRoot(dirName, (firstUnderscore == 0) ? dirName : firstUnderscore + 1);
+    StringRange dirRoot(dirName, (firstUnderscore == 0) ? dirName : firstUnderscore + 1);
 
     // do we shrink the menus?
     // we shrink only if we have at least two things to shrink :-)
@@ -218,16 +218,15 @@ void TextureGroupsMenu_Construct(GtkMenu* menu, const TextureGroups& groups)
     ++next;
     if(firstUnderscore != 0
       && next != groups.end()
-      && string_equal_start((*next).c_str(), dirRoot.c_str()))
+      && string_equal_start((*next).c_str(), dirRoot))
     {
-      CopiedString itemName(dirName, firstUnderscore);
-           GtkMenuItem* item = Menu_addItem(menu, itemName.c_str());
+           GtkMenuItem* item = Menu_addItem(menu, CopiedString(StringRange(dirName, firstUnderscore)).c_str());
 
            GtkMenu *pSubMenu = GTK_MENU(gtk_menu_new());
       gtk_menu_item_set_submenu(item, GTK_WIDGET(pSubMenu));
 
            // keep going...
-           while(i != groups.end() && string_equal_start((*i).c_str(), dirRoot.c_str()))
+           while(i != groups.end() && string_equal_start((*i).c_str(), dirRoot))
            {
              TextureGroupsMenu_addItem(pSubMenu, (*i).c_str());
 
@@ -266,7 +265,7 @@ void TextureGroups_addShader(TextureGroups& groups, const char* shaderName)
     const char* last = path_remove_directory(texture);
     if(!string_empty(last))
     {
-      groups.insert(CopiedString(texture, --last));
+      groups.insert(CopiedString(StringRange(texture, --last)));
     }
   }
 }
@@ -811,8 +810,7 @@ class LoadShaderVisitor : public Archive::Visitor
 public:
   void visit(const char* name)
   {
-    CopiedString shaderName(name, path_get_filename_base_end(name));
-    IShader* shader = QERApp_Shader_ForName(shaderName.c_str());
+    IShader* shader = QERApp_Shader_ForName(CopiedString(StringRange(name, path_get_filename_base_end(name))).c_str());
     shader->DecRef();
   }
 };
index d80787d..b0c2c05 100644 (file)
@@ -1152,7 +1152,7 @@ public:
         {
           popMenu();
         }
-        pushMenu(CopiedString(name, underscore));
+        pushMenu(CopiedString(StringRange(name, underscore)));
       }
       else if(m_stack.size() == 2)
       {