mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
added order_by support to position function, orders are cached; TODO: clear the cache when a card changes
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@109 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+37
-14
@@ -14,6 +14,7 @@
|
||||
#include <data/field.hpp>
|
||||
#include <data/field/text.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/script_manager.hpp>
|
||||
#include <wx/sstream.h>
|
||||
@@ -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) {
|
||||
tag.addAlias(300, _("style"), _("stylesheet")); // < 0.3.0 used style instead of stylesheet
|
||||
tag.addAlias(300, _("extra set info"), _("styling"));
|
||||
@@ -135,6 +122,42 @@ IMPLEMENT_REFLECTION(Set) {
|
||||
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
|
||||
|
||||
// Extra set data, for a specific stylesheet
|
||||
|
||||
@@ -23,9 +23,12 @@ DECLARE_POINTER_TYPE(Styling);
|
||||
DECLARE_POINTER_TYPE(Field);
|
||||
DECLARE_POINTER_TYPE(Value);
|
||||
DECLARE_POINTER_TYPE(Keyword);
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(ScriptValue);
|
||||
class ScriptManager;
|
||||
class Context;
|
||||
class Dependency;
|
||||
template <typename> class OrderCache;
|
||||
typedef shared_ptr<OrderCache<CardP> > OrderCacheP;
|
||||
|
||||
// ----------------------------------------------------------------------------- : Set
|
||||
|
||||
@@ -81,6 +84,9 @@ class Set : public Packaged {
|
||||
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:
|
||||
virtual String typeName() const;
|
||||
virtual void validate(Version);
|
||||
@@ -89,11 +95,14 @@ class Set : public Packaged {
|
||||
private:
|
||||
/// Object for managing and executing scripts
|
||||
scoped_ptr<ScriptManager> script_manager;
|
||||
/// Cache of cards ordered by some criterion
|
||||
map<ScriptValueP,OrderCacheP> order_cache;
|
||||
};
|
||||
|
||||
inline int item_count(const Set& set) {
|
||||
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(Set* value, const String& name, const Dependency& dep);
|
||||
|
||||
@@ -378,7 +378,7 @@ void TextValueEditor::showCaret() {
|
||||
// it is not 0 for empty text, because TextRenderer handles that case
|
||||
if (cursor.height == 0) {
|
||||
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;
|
||||
} else {
|
||||
cursor.height = v.heightOfLastLine();
|
||||
|
||||
@@ -1135,6 +1135,9 @@
|
||||
<File
|
||||
RelativePath=".\util\for_each.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\order_cache.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\prec.hpp">
|
||||
</File>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <script/value.hpp>
|
||||
#include <script/context.hpp>
|
||||
#include <util/tagged_string.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <wx/regex.h>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(UInt);
|
||||
@@ -370,14 +371,53 @@ SCRIPT_RULE_1(tag_remove, String, tag) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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
|
||||
/** 0 based index, -1 if not found */
|
||||
int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) {
|
||||
ScriptType of_t = of->type(), in_t = in->type();
|
||||
if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) {
|
||||
// string finding
|
||||
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
|
||||
|
||||
@@ -29,7 +29,7 @@ ScriptValueP ScriptValue::dependencies(Context&, const Dependency&
|
||||
|
||||
// ----------------------------------------------------------------------------- : Iterators
|
||||
|
||||
ScriptType ScriptIterator::type() const { return SCRIPT_OBJECT; }
|
||||
ScriptType ScriptIterator::type() const { return SCRIPT_ITERATOR; }
|
||||
String ScriptIterator::typeName() const { return _("iterator"); }
|
||||
|
||||
// Iterator over a range of integers
|
||||
|
||||
+17
-5
@@ -10,6 +10,7 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/reflect.hpp>
|
||||
#include <util/error.hpp>
|
||||
class Context;
|
||||
class Dependency;
|
||||
@@ -37,7 +38,9 @@ enum ScriptType
|
||||
, SCRIPT_COLOR
|
||||
, SCRIPT_IMAGE
|
||||
, SCRIPT_FUNCTION
|
||||
, SCRIPT_OBJECT
|
||||
, SCRIPT_OBJECT // Only ScriptObject
|
||||
, SCRIPT_COLLECTION
|
||||
, SCRIPT_ITERATOR
|
||||
, SCRIPT_DUMMY
|
||||
};
|
||||
|
||||
@@ -121,7 +124,7 @@ extern ScriptValueP dependency_dummy; ///< Dummy value used during dependency an
|
||||
|
||||
// Iterator over a collection
|
||||
struct ScriptIterator : public ScriptValue {
|
||||
virtual ScriptType type() const;// { return SCRIPT_OBJECT; }
|
||||
virtual ScriptType type() const;// { return SCRIPT_ITERATOR; }
|
||||
virtual String typeName() const;// { return "iterator"; }
|
||||
|
||||
/// Return the next item for this iterator, or ScriptValueP() if there is no such item
|
||||
@@ -155,7 +158,7 @@ template <typename Collection>
|
||||
class ScriptCollection : public ScriptValue {
|
||||
public:
|
||||
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 ScriptValueP getMember(const String& name) const {
|
||||
long index;
|
||||
@@ -201,7 +204,7 @@ template <typename Collection>
|
||||
class ScriptMap : public ScriptValue {
|
||||
public:
|
||||
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 ScriptValueP getMember(const String& name) const {
|
||||
return get_member(*value, name);
|
||||
@@ -219,6 +222,11 @@ template <typename T>
|
||||
int item_count(const T& v) {
|
||||
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
|
||||
template <typename T>
|
||||
@@ -253,12 +261,16 @@ class ScriptObject : public ScriptValue {
|
||||
mark_dependency_member(value, name, dep);
|
||||
return getMember(name);
|
||||
}
|
||||
virtual ScriptValueP makeIterator() const {
|
||||
ScriptValueP it = make_iterator(*value);
|
||||
return it ? it : ScriptValue::makeIterator();
|
||||
}
|
||||
virtual int itemCount() const {
|
||||
int i = item_count(*value);
|
||||
return i >= 0 ? i : ScriptValue::itemCount();
|
||||
}
|
||||
/// Get access to the value
|
||||
inline T getValue() { return value; }
|
||||
inline T getValue() const { return value; }
|
||||
private:
|
||||
T value; ///< The object
|
||||
ScriptValueP getDefault() const {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
Reference in New Issue
Block a user