virtual bool getShowNames() = 0;
virtual void setShowAngles(bool showAngles) = 0;
virtual bool getShowAngles() = 0;
+
+ virtual void printStatistics() const = 0;
};
#include "modulesystem.h"
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;
increment();
return tmp;
}
- value_type& operator*()
+ value_type& operator*() const
{
return m_node->m_value;
}
- value_type* operator->()
+ value_type* operator->() const
{
return &(operator*());
}
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))
{
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))
{
#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"
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;
(*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);
: 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
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);
}
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))
typedef ArrayConstRange<const char*> StringArrayRange;
#define STRING_ARRAY_RANGE(array) (StringArrayRange(array, ARRAY_END(array)))
+typedef ArrayRange<const char> StringRange;
+
#endif
#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
#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;
}
};
-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
}
};
-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.
/// 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
}
};
-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();
}
};
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));
<Filter
Name="string"
Filter="">
+ <File
+ RelativePath=".\string\pooledstring.cpp">
+ </File>
+ <File
+ RelativePath=".\string\pooledstring.h">
+ </File>
<File
RelativePath=".\string\string.cpp">
</File>
}
-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;
}
#include <algorithm>
#include "memory/allocator.h"
+#include "generic/arrayrange.h"
/// \brief Returns true if \p string length is zero.
/// O(1)
/// \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;
}
/// \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;
: Buffer(string)
{
}
- String(const char* first, const char* last)
- : Buffer(first, last)
+ String(StringRange range)
+ : Buffer(range)
{
}
temp.swap(*this);
return *this;
}
+ String& operator=(StringRange range)
+ {
+ String temp(range);
+ temp.swap(*this);
+ return *this;
+ }
void swap(String& other)
{
{
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)
{
: 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
{
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;
}
{
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);
}
end = p;
}
- return name_t(CopiedString(name, end), Postfix(end));
+ return name_t(CopiedString(StringRange(name, end)), Postfix(end));
}
{
return g_showAngles;
}
+
+ void printStatistics() const
+ {
+ StringPool_analyse(EntityKeyValues::getPool());
+ }
};
Quake3EntityCreator g_Quake3EntityCreator;
{
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
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;
}
};
{
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
#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"
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)
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();
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)
-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
{
};
-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));
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)
{
public:
LayerTypeId m_type;
- CopiedString m_texture;
+ TextureExpression m_texture;
BlendFuncExpression m_blendFunc;
bool m_clampToBorder;
ShaderValue m_alphaTest;
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
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)
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();
{
public:
LayerTypeId m_type;
- CopiedString m_texture;
+ TextureExpression m_texture;
BlendFunc m_blendFunc;
bool m_clampToBorder;
float m_alphaTest;
lst = lst->next;
}
}
+
+ //StringPool_analyse(ShaderPool::instance());
}
void Shaders_Free()
}
else // special key
{
- CopiedString keyName(value, keyEnd);
+ CopiedString keyName(StringRange(value, keyEnd));
accelerator.key = global_keys_find(keyName.c_str());
if(accelerator.key != 0)
{
{
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);
}
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);
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,
where = strchr(pText,'\"');
if (where)
{
- p = CopiedString(pText, where);
+ p = StringRange(pText, where);
}
else
{
const char* key = tokeniser.getToken();
const char* last = string_findFirstSpaceOrTab(key);
- CopiedString first(key, last);
+ CopiedString first(StringRange(key, last));
if(!string_empty(last))
{
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
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)
{
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 :-)
++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());
const char* last = path_remove_directory(texture);
if(!string_empty(last))
{
- groups.insert(CopiedString(texture, --last));
+ groups.insert(CopiedString(StringRange(texture, --last)));
}
}
}
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();
}
};
{
popMenu();
}
- pushMenu(CopiedString(name, underscore));
+ pushMenu(CopiedString(StringRange(name, underscore)));
}
else if(m_stack.size() == 2)
{