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 @@
#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
......
......@@ -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 {
......
//+----------------------------------------------------------------------------+
//| 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