Commit 7090b6cd authored by twanvl's avatar twanvl

added order_by support to position function, orders are cached; TODO: clear...

added order_by support to position function, orders are cached; TODO: clear the cache when a card changes
parent 4265533b
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <data/field.hpp> #include <data/field.hpp>
#include <data/field/text.hpp> // for 0.2.7 fix #include <data/field/text.hpp> // for 0.2.7 fix
#include <util/tagged_string.hpp> // for 0.2.7 fix #include <util/tagged_string.hpp> // for 0.2.7 fix
#include <util/order_cache.hpp>
#include <script/value.hpp> #include <script/value.hpp>
#include <script/script_manager.hpp> #include <script/script_manager.hpp>
#include <wx/sstream.h> #include <wx/sstream.h>
...@@ -100,20 +101,6 @@ void Set::validate(Version file_app_version) { ...@@ -100,20 +101,6 @@ void Set::validate(Version file_app_version) {
*/ } */ }
} }
void mark_dependency_member(Set* value, const String& name, const Dependency& dep) {
// TODO
}
void mark_dependency_member(const SetP& value, const String& name, const Dependency& dep) {
mark_dependency_member(value.get(), name, dep);
}
// in scripts, set.something is read from the set_info
template <typename Tag>
void reflect_set_info_get_member(Tag& tag, const IndexMap<FieldP, ValueP>& data) {}
void reflect_set_info_get_member(GetMember& tag, const IndexMap<FieldP, ValueP>& data) {
REFLECT_NAMELESS(data);
}
IMPLEMENT_REFLECTION(Set) { IMPLEMENT_REFLECTION(Set) {
tag.addAlias(300, _("style"), _("stylesheet")); // < 0.3.0 used style instead of stylesheet tag.addAlias(300, _("style"), _("stylesheet")); // < 0.3.0 used style instead of stylesheet
tag.addAlias(300, _("extra set info"), _("styling")); tag.addAlias(300, _("extra set info"), _("styling"));
...@@ -135,6 +122,42 @@ IMPLEMENT_REFLECTION(Set) { ...@@ -135,6 +122,42 @@ IMPLEMENT_REFLECTION(Set) {
REFLECT(apprentice_code); REFLECT(apprentice_code);
} }
// ----------------------------------------------------------------------------- : Script utilities
ScriptValueP make_iterator(const Set& set) {
return new_intrusive1<ScriptCollectionIterator<vector<CardP> > >(&set.cards);
}
void mark_dependency_member(Set* value, const String& name, const Dependency& dep) {
// TODO
}
void mark_dependency_member(const SetP& value, const String& name, const Dependency& dep) {
mark_dependency_member(value.get(), name, dep);
}
// in scripts, set.something is read from the set_info
template <typename Tag>
void reflect_set_info_get_member(Tag& tag, const IndexMap<FieldP, ValueP>& data) {}
void reflect_set_info_get_member(GetMember& tag, const IndexMap<FieldP, ValueP>& data) {
REFLECT_NAMELESS(data);
}
int Set::positionOfCard(const CardP& card, const ScriptValueP& order_by) {
// TODO : Lock the map?
assert(order_by);
OrderCacheP& order = order_cache[order_by];
if (!order) {
// 1. make a list of the order value for each card
vector<String> values; values.reserve(cards.size());
FOR_EACH_CONST(c, cards) {
values.push_back(*order_by->eval(getContext(c)));
}
// 2. initialize order cache
order.reset(new OrderCache<CardP>(cards, values));
}
return order->find(card);
}
// ----------------------------------------------------------------------------- : Styling // ----------------------------------------------------------------------------- : Styling
// Extra set data, for a specific stylesheet // Extra set data, for a specific stylesheet
......
...@@ -23,9 +23,12 @@ DECLARE_POINTER_TYPE(Styling); ...@@ -23,9 +23,12 @@ DECLARE_POINTER_TYPE(Styling);
DECLARE_POINTER_TYPE(Field); DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Value); DECLARE_POINTER_TYPE(Value);
DECLARE_POINTER_TYPE(Keyword); DECLARE_POINTER_TYPE(Keyword);
DECLARE_INTRUSIVE_POINTER_TYPE(ScriptValue);
class ScriptManager; class ScriptManager;
class Context; class Context;
class Dependency; class Dependency;
template <typename> class OrderCache;
typedef shared_ptr<OrderCache<CardP> > OrderCacheP;
// ----------------------------------------------------------------------------- : Set // ----------------------------------------------------------------------------- : Set
...@@ -81,6 +84,9 @@ class Set : public Packaged { ...@@ -81,6 +84,9 @@ class Set : public Packaged {
throw InternalError(_("Expected a set field with name '")+name+_("'")); throw InternalError(_("Expected a set field with name '")+name+_("'"));
} }
/// Find the position of a card in this set, when the card list is sorted using the given cirterium
int positionOfCard(const CardP& card, const ScriptValueP& order_by);
protected: protected:
virtual String typeName() const; virtual String typeName() const;
virtual void validate(Version); virtual void validate(Version);
...@@ -89,11 +95,14 @@ class Set : public Packaged { ...@@ -89,11 +95,14 @@ class Set : public Packaged {
private: private:
/// Object for managing and executing scripts /// Object for managing and executing scripts
scoped_ptr<ScriptManager> script_manager; scoped_ptr<ScriptManager> script_manager;
/// Cache of cards ordered by some criterion
map<ScriptValueP,OrderCacheP> order_cache;
}; };
inline int item_count(const Set& set) { inline int item_count(const Set& set) {
return (int)set.cards.size(); return (int)set.cards.size();
} }
ScriptValueP make_iterator(const Set& set);
void mark_dependency_member(const SetP& value, const String& name, const Dependency& dep); void mark_dependency_member(const SetP& value, const String& name, const Dependency& dep);
void mark_dependency_member(Set* value, const String& name, const Dependency& dep); void mark_dependency_member(Set* value, const String& name, const Dependency& dep);
......
...@@ -378,7 +378,7 @@ void TextValueEditor::showCaret() { ...@@ -378,7 +378,7 @@ void TextValueEditor::showCaret() {
// it is not 0 for empty text, because TextRenderer handles that case // it is not 0 for empty text, because TextRenderer handles that case
if (cursor.height == 0) { if (cursor.height == 0) {
if (style().always_symbol && style().symbol_font.valid()) { if (style().always_symbol && style().symbol_font.valid()) {
RealSize s = style().symbol_font.font->defaultSymbolSize(viewer.getContext(), rot.trS(1)); RealSize s = style().symbol_font.font->defaultSymbolSize(viewer.getContext(), rot.trS(style().symbol_font.size));
cursor.height = s.height; cursor.height = s.height;
} else { } else {
cursor.height = v.heightOfLastLine(); cursor.height = v.heightOfLastLine();
......
...@@ -1135,6 +1135,9 @@ ...@@ -1135,6 +1135,9 @@
<File <File
RelativePath=".\util\for_each.hpp"> RelativePath=".\util\for_each.hpp">
</File> </File>
<File
RelativePath=".\util\order_cache.hpp">
</File>
<File <File
RelativePath=".\util\prec.hpp"> RelativePath=".\util\prec.hpp">
</File> </File>
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <script/value.hpp> #include <script/value.hpp>
#include <script/context.hpp> #include <script/context.hpp>
#include <util/tagged_string.hpp> #include <util/tagged_string.hpp>
#include <data/set.hpp>
#include <wx/regex.h> #include <wx/regex.h>
DECLARE_TYPEOF_COLLECTION(UInt); DECLARE_TYPEOF_COLLECTION(UInt);
...@@ -370,14 +371,53 @@ SCRIPT_RULE_1(tag_remove, String, tag) { ...@@ -370,14 +371,53 @@ SCRIPT_RULE_1(tag_remove, String, tag) {
// ----------------------------------------------------------------------------- : Vector stuff // ----------------------------------------------------------------------------- : Vector stuff
/// compare script values for equallity
bool equal(const ScriptValue& a, const ScriptValue& b) {
ScriptType at = a.type(), bt = b.type();
if (at != bt) {
return false;
} else if (at == SCRIPT_INT) {
return (int)a == (int)b;
} else if (at == SCRIPT_DOUBLE) {
return (double)a == (double)b;
} else if (at == SCRIPT_STRING) {
return (String)a == (String)b;
} else if (at == SCRIPT_OBJECT) {
// HACK for ScriptObject<shared_ptr<X> >
// assumes different types are layed out the same, and that
// should be void*, but then we need getMember for void
const ScriptObject<int*>& av = reinterpret_cast<const ScriptObject<int*>&>(a);
const ScriptObject<int*>& bv = reinterpret_cast<const ScriptObject<int*>&>(b);
return av.getValue() == bv.getValue();
}
return &a == &b;
}
/// position of some element in a vector /// position of some element in a vector
/** 0 based index, -1 if not found */ /** 0 based index, -1 if not found */
int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) { int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) {
ScriptType of_t = of->type(), in_t = in->type(); ScriptType of_t = of->type(), in_t = in->type();
if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) { if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) {
// string finding
return (int)((String)*of).find(*in); // (int)npos == -1 return (int)((String)*of).find(*in); // (int)npos == -1
} else if (order_by) {
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
if (s && c) {
return s->getValue()->positionOfCard(c->getValue(), order_by);
} else {
throw ScriptError(_("position: using 'order_by' is only supported for finding cards in the set"));
}
} else {
// unordered position
ScriptValueP it = in->makeIterator();
int i = 0;
while (ScriptValueP v = it->next()) {
if (equal(*of, *v)) return i;
i++;
}
} }
return -1; // TODO return -1; // TODO?
} }
// finding positions, also of substrings // finding positions, also of substrings
......
...@@ -29,7 +29,7 @@ ScriptValueP ScriptValue::dependencies(Context&, const Dependency& ...@@ -29,7 +29,7 @@ ScriptValueP ScriptValue::dependencies(Context&, const Dependency&
// ----------------------------------------------------------------------------- : Iterators // ----------------------------------------------------------------------------- : Iterators
ScriptType ScriptIterator::type() const { return SCRIPT_OBJECT; } ScriptType ScriptIterator::type() const { return SCRIPT_ITERATOR; }
String ScriptIterator::typeName() const { return _("iterator"); } String ScriptIterator::typeName() const { return _("iterator"); }
// Iterator over a range of integers // Iterator over a range of integers
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/reflect.hpp>
#include <util/error.hpp> #include <util/error.hpp>
class Context; class Context;
class Dependency; class Dependency;
...@@ -37,7 +38,9 @@ enum ScriptType ...@@ -37,7 +38,9 @@ enum ScriptType
, SCRIPT_COLOR , SCRIPT_COLOR
, SCRIPT_IMAGE , SCRIPT_IMAGE
, SCRIPT_FUNCTION , SCRIPT_FUNCTION
, SCRIPT_OBJECT , SCRIPT_OBJECT // Only ScriptObject
, SCRIPT_COLLECTION
, SCRIPT_ITERATOR
, SCRIPT_DUMMY , SCRIPT_DUMMY
}; };
...@@ -121,7 +124,7 @@ extern ScriptValueP dependency_dummy; ///< Dummy value used during dependency an ...@@ -121,7 +124,7 @@ extern ScriptValueP dependency_dummy; ///< Dummy value used during dependency an
// Iterator over a collection // Iterator over a collection
struct ScriptIterator : public ScriptValue { struct ScriptIterator : public ScriptValue {
virtual ScriptType type() const;// { return SCRIPT_OBJECT; } virtual ScriptType type() const;// { return SCRIPT_ITERATOR; }
virtual String typeName() const;// { return "iterator"; } virtual String typeName() const;// { return "iterator"; }
/// Return the next item for this iterator, or ScriptValueP() if there is no such item /// Return the next item for this iterator, or ScriptValueP() if there is no such item
...@@ -155,7 +158,7 @@ template <typename Collection> ...@@ -155,7 +158,7 @@ template <typename Collection>
class ScriptCollection : public ScriptValue { class ScriptCollection : public ScriptValue {
public: public:
inline ScriptCollection(const Collection* v) : value(v) {} inline ScriptCollection(const Collection* v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_OBJECT; } virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _("collection"); } virtual String typeName() const { return _("collection"); }
virtual ScriptValueP getMember(const String& name) const { virtual ScriptValueP getMember(const String& name) const {
long index; long index;
...@@ -201,7 +204,7 @@ template <typename Collection> ...@@ -201,7 +204,7 @@ template <typename Collection>
class ScriptMap : public ScriptValue { class ScriptMap : public ScriptValue {
public: public:
inline ScriptMap(const Collection* v) : value(v) {} inline ScriptMap(const Collection* v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_OBJECT; } virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _("collection"); } virtual String typeName() const { return _("collection"); }
virtual ScriptValueP getMember(const String& name) const { virtual ScriptValueP getMember(const String& name) const {
return get_member(*value, name); return get_member(*value, name);
...@@ -219,6 +222,11 @@ template <typename T> ...@@ -219,6 +222,11 @@ template <typename T>
int item_count(const T& v) { int item_count(const T& v) {
return -1; return -1;
} }
/// Return an iterator for some collection, can be overloaded
template <typename T>
ScriptValueP make_iterator(const T& v) {
return ScriptValueP();
}
/// Mark a dependency on a member of value, can be overloaded /// Mark a dependency on a member of value, can be overloaded
template <typename T> template <typename T>
...@@ -253,12 +261,16 @@ class ScriptObject : public ScriptValue { ...@@ -253,12 +261,16 @@ class ScriptObject : public ScriptValue {
mark_dependency_member(value, name, dep); mark_dependency_member(value, name, dep);
return getMember(name); return getMember(name);
} }
virtual ScriptValueP makeIterator() const {
ScriptValueP it = make_iterator(*value);
return it ? it : ScriptValue::makeIterator();
}
virtual int itemCount() const { virtual int itemCount() const {
int i = item_count(*value); int i = item_count(*value);
return i >= 0 ? i : ScriptValue::itemCount(); return i >= 0 ? i : ScriptValue::itemCount();
} }
/// Get access to the value /// Get access to the value
inline T getValue() { return value; } inline T getValue() const { return value; }
private: private:
T value; ///< The object T value; ///< The object
ScriptValueP getDefault() const { ScriptValueP getDefault() const {
......
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_ORDER_CACHE
#define HEADER_UTIL_ORDER_CACHE
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
// ----------------------------------------------------------------------------- : OrderCache
/// Object that cashes an ordered version of a list of items, for finding the position of objects
/** Can be used as a map "void* -> int" for finding the position of an object */
template <typename T>
class OrderCache {
public:
/// Initialize the order cache, ordering the keys by their string values from the other vector
/** @pre keys.size() == values.size() */
OrderCache(const vector<T>& keys, const vector<String>& values);
/// Find the position of the given key in the cache, returns -1 if not found
int find(const T& key) const;
private:
struct CompareKeys;
struct CompareValues;
typedef pair<void*,int> KV;
vector<KV> positions;
};
// ----------------------------------------------------------------------------- : Implementation
template <typename T>
struct OrderCache<T>::CompareKeys {
inline bool operator () (const KV& a, void* b) { return a.first < b; }
inline bool operator () (const KV& a, const KV& b) { return a.first < b.first; }
inline bool operator () (void* a, const KV& b) { return a < b.first; }
};
template <typename T>
struct OrderCache<T>::CompareValues {
const vector<String>& values;
CompareValues(const vector<String>& values) : values(values) {}
inline bool operator () (const KV& a, const KV& b) {
return values[a.second] < values[b.second];
}
};
template <typename T>
OrderCache<T>::OrderCache(const vector<T>& keys, const vector<String>& values) {
assert(keys.size() == values.size());
// initialize positions, use pos to point back to the values vector
positions.reserve(keys.size());
int i = 0;
for (vector<T>::const_iterator it = keys.begin() ; it != keys.end() ; ++it, ++i) {
positions.push_back(KV(&**it, i));
}
// sort the KVs by the values
sort(positions.begin(), positions.end(), CompareValues(values));
// update positions, to point to sorted list
i = 0;
for (vector<KV>::iterator it = positions.begin() ; it != positions.end() ; ++it, ++i) {
it->second = i;
}
// sort the KVs by the keys
sort(positions.begin(), positions.end(), CompareKeys());
}
template <typename T>
int OrderCache<T>::find(const T& key) const {
vector<KV>::const_iterator it = lower_bound(positions.begin(), positions.end(), &*key, CompareKeys());
if (it == positions.end() || it->first != &*key) return -1;
return it->second;
}
// ----------------------------------------------------------------------------- : EOF
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment