Commit c3dfc73e authored by twanvl's avatar twanvl

Support for extra card fields in stylesheets;

Fixed some bugs:
 - Missing choice images can crash mse.
 - The wrong style is used for making preview choice images on style panel.
FOR_EACH(x, *y.z) should now work without parentheses on linux as well.
parent 4d7f4687
...@@ -34,6 +34,9 @@ class Card : public IntrusivePtrVirtualBase { ...@@ -34,6 +34,9 @@ class Card : public IntrusivePtrVirtualBase {
/// The values on the fields of the card. /// The values on the fields of the card.
/** The indices should correspond to the card_fields in the Game */ /** The indices should correspond to the card_fields in the Game */
IndexMap<FieldP, ValueP> data; IndexMap<FieldP, ValueP> data;
/// The values on the extra fields of the card.
/** The indices should correspond to the extra_card_fields in the StyleSheet */
IndexMap<FieldP, ValueP> extra_data;
/// Notes for this card /// Notes for this card
String notes; String notes;
/// Alternative style to use for this card /// Alternative style to use for this card
......
...@@ -53,7 +53,7 @@ Context& Set::getContext(const CardP& card) { ...@@ -53,7 +53,7 @@ Context& Set::getContext(const CardP& card) {
assert(wxThread::IsMain()); assert(wxThread::IsMain());
return script_manager->getContext(card); return script_manager->getContext(card);
} }
void Set::updateFor(const CardP& card) { void Set::updateStyles(const CardP& card) {
script_manager->updateStyles(card); script_manager->updateStyles(card);
} }
void Set::updateDelayed() { void Set::updateDelayed() {
......
...@@ -66,8 +66,8 @@ class Set : public Packaged { ...@@ -66,8 +66,8 @@ class Set : public Packaged {
/// A context for performing scripts on a particular card /// A context for performing scripts on a particular card
/** Should only be used from the main thread! */ /** Should only be used from the main thread! */
Context& getContext(const CardP& card); Context& getContext(const CardP& card);
/// Update styles for a card /// Update styles and extra_card_fields for a card
void updateFor(const CardP& card); void updateStyles(const CardP& card);
/// Update scripts that were delayed /// Update scripts that were delayed
void updateDelayed(); void updateDelayed();
/// A context for performing scripts /// A context for performing scripts
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
DECLARE_TYPEOF_COLLECTION(StyleSheet*); DECLARE_TYPEOF_COLLECTION(StyleSheet*);
DECLARE_TYPEOF_COLLECTION(FieldP);
// ----------------------------------------------------------------------------- : StyleSheet // ----------------------------------------------------------------------------- : StyleSheet
...@@ -62,22 +63,35 @@ IMPLEMENT_REFLECTION(StyleSheet) { ...@@ -62,22 +63,35 @@ IMPLEMENT_REFLECTION(StyleSheet) {
REFLECT(game); REFLECT(game);
REFLECT_BASE(Packaged); REFLECT_BASE(Packaged);
REFLECT(init_script);
REFLECT(card_width); REFLECT(card_width);
REFLECT(card_height); REFLECT(card_height);
REFLECT(card_dpi); REFLECT(card_dpi);
REFLECT(card_background); REFLECT(card_background);
REFLECT(init_script);
// styling
REFLECT(styling_fields);
REFLECT_IF_READING styling_style.init(styling_fields);
REFLECT(styling_style);
// style of game fields
if (game) { if (game) {
REFLECT_IF_READING { REFLECT_IF_READING {
card_style.init(game->card_fields); card_style.init(game->card_fields);
set_info_style.cloneFrom(game->default_set_style); set_info_style.cloneFrom(game->default_set_style);
} }
REFLECT(card_style);
REFLECT(set_info_style); REFLECT(set_info_style);
REFLECT(card_style);
} }
REFLECT(styling_fields); // extra card fields
REFLECT_IF_READING styling_style.init(styling_fields); REFLECT(extra_card_fields);
REFLECT(styling_style); REFLECT_IF_READING {
if (extra_card_style.init(extra_card_fields)) {
// make sure the extra_card_fields are not editable and savable
FOR_EACH(f, extra_card_fields) {
f->editable = f->save_value = false;
}
}
}
REFLECT(extra_card_style);
} }
......
...@@ -38,7 +38,10 @@ class StyleSheet : public Packaged { ...@@ -38,7 +38,10 @@ class StyleSheet : public Packaged {
/// The styling for set info fields /// The styling for set info fields
/** The indices should correspond to the set_fields in the Game */ /** The indices should correspond to the set_fields in the Game */
IndexMap<FieldP, StyleP> set_info_style; IndexMap<FieldP, StyleP> set_info_style;
/// Extra fields for styling /// Extra card fields for boxes and borders
vector<FieldP> extra_card_fields;
IndexMap<FieldP, StyleP> extra_card_style;
/// Extra fields for styling options
vector<FieldP> styling_fields; vector<FieldP> styling_fields;
/// The styling for the extra set fields /// The styling for the extra set fields
/** The indices should correspond to the styling_fields */ /** The indices should correspond to the styling_fields */
......
...@@ -79,7 +79,7 @@ GraphData::GraphData(const GraphDataPre& d) ...@@ -79,7 +79,7 @@ GraphData::GraphData(const GraphDataPre& d)
} }
} else if (a->order) { } else if (a->order) {
// specific group order // specific group order
FOR_EACH_CONST(gn, (*(a->order))) { FOR_EACH_CONST(gn, *a->order) {
UInt count = counts[gn]; UInt count = counts[gn];
a->groups.push_back(GraphGroup(gn, count)); a->groups.push_back(GraphGroup(gn, count));
a->max = max(a->max, count); a->max = max(a->max, count);
......
...@@ -192,7 +192,7 @@ StylingEditor::StylingEditor(Window* parent, int id, long style) ...@@ -192,7 +192,7 @@ StylingEditor::StylingEditor(Window* parent, int id, long style)
{} {}
void StylingEditor::showStylesheet(const StyleSheetP& stylesheet) { void StylingEditor::showStylesheet(const StyleSheetP& stylesheet) {
setStyles(set->stylesheet, stylesheet->styling_style); setStyles(stylesheet, stylesheet->styling_style);
setData(set->stylingDataFor(*stylesheet)); setData(set->stylingDataFor(*stylesheet));
} }
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp> #include <util/prec.hpp>
#include <wx/spinctrl.h>
class ImageSlicePreview; class ImageSlicePreview;
class ImageSliceSelector; class ImageSliceSelector;
class wxSpinEvent; class wxSpinEvent;
class wxSpinCtrl;
DECLARE_POINTER_TYPE(AlphaMask); DECLARE_POINTER_TYPE(AlphaMask);
// ----------------------------------------------------------------------------- : ImageSlice // ----------------------------------------------------------------------------- : ImageSlice
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <gui/thumbnail_thread.hpp> #include <gui/thumbnail_thread.hpp>
#include <util/platform.hpp> #include <util/platform.hpp>
#include <util/error.hpp>
#include <wx/thread.h> #include <wx/thread.h>
typedef pair<ThumbnailRequestP,Image> pair_ThumbnailRequestP_Image; typedef pair<ThumbnailRequestP,Image> pair_ThumbnailRequestP_Image;
...@@ -71,7 +72,13 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() { ...@@ -71,7 +72,13 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() {
parent->open_requests.pop_front(); parent->open_requests.pop_front();
} }
// perform request // perform request
Image img = current->generate(); Image img;
try {
img = current->generate();
} catch (const Error& e) {
handle_error(e, false, false);
} catch (...) {
}
// store in cache // store in cache
if (img.Ok()) { if (img.Ok()) {
String filename = image_cache_dir() + safe_filename(current->cache_name) + _(".png"); String filename = image_cache_dir() + safe_filename(current->cache_name) + _(".png");
......
...@@ -196,8 +196,13 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) { ...@@ -196,8 +196,13 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) {
} }
break; break;
default: default:
#ifdef __WXMSW__
if (ev.GetKeyCode() >= _(' ') && ev.GetKeyCode() == (int)ev.GetRawKeyCode()) {
// This check is need, otherwise pressing a key, say "0" on the numpad produces "a0"
// (don't ask me why)
#else
if (ev.GetKeyCode() >= _(' ') /*&& ev.GetKeyCode() == (int)ev.GetRawKeyCode()*/) { if (ev.GetKeyCode() >= _(' ') /*&& ev.GetKeyCode() == (int)ev.GetRawKeyCode()*/) {
// if (ev.GetKeyCode() >= _(' ') && ev.GetKeyCode() == (int)ev.GetRawKeyCode()) { #endif
// TODO: Find a more correct way to determine normal characters, // TODO: Find a more correct way to determine normal characters,
// this might not work for internationalized input. // this might not work for internationalized input.
// It might also not be portable! // It might also not be portable!
......
...@@ -2506,6 +2506,9 @@ ...@@ -2506,6 +2506,9 @@
<Filter <Filter
Name="base" Name="base"
Filter=""> Filter="">
<File
RelativePath=".\script\dependency.hpp">
</File>
<File <File
RelativePath=".\script\script.cpp"> RelativePath=".\script\script.cpp">
</File> </File>
...@@ -2534,9 +2537,6 @@ ...@@ -2534,9 +2537,6 @@
<File <File
RelativePath=".\script\dependency.cpp"> RelativePath=".\script\dependency.cpp">
</File> </File>
<File
RelativePath=".\script\dependency.hpp">
</File>
<File <File
RelativePath=".\script\parser.cpp"> RelativePath=".\script\parser.cpp">
</File> </File>
......
...@@ -41,12 +41,16 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) { ...@@ -41,12 +41,16 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) {
clearDC(dc.getDC(), background); clearDC(dc.getDC(), background);
// update style scripts // update style scripts
try { try {
if (card) {
set->updateStyles(card);
} else {
Context& ctx = getContext(); Context& ctx = getContext();
FOR_EACH(v, viewers) { FOR_EACH(v, viewers) {
if (v->getStyle()->update(ctx)) { if (v->getStyle()->update(ctx)) {
v->getStyle()->tellListeners(); v->getStyle()->tellListeners();
} }
} }
}
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e, false, false);
} }
...@@ -91,8 +95,9 @@ void DataViewer::setCard(const CardP& card, bool refresh) { ...@@ -91,8 +95,9 @@ void DataViewer::setCard(const CardP& card, bool refresh) {
assert(set); assert(set);
this->card = card; this->card = card;
stylesheet = new_stylesheet; stylesheet = new_stylesheet;
setStyles(stylesheet, stylesheet->card_style); setStyles(stylesheet, stylesheet->card_style, &stylesheet->extra_card_style);
setData(card->data); card->extra_data.init(stylesheet->extra_card_fields); // make sure extra_data is initialized
setData(card->data, &card->extra_data);
onChangeSize(); onChangeSize();
} }
...@@ -111,7 +116,7 @@ struct CompareViewer { ...@@ -111,7 +116,7 @@ struct CompareViewer {
} }
}; };
void DataViewer::setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP>& styles) { void DataViewer::setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP>& styles, IndexMap<FieldP,StyleP>* extra_styles) {
if (!viewers.empty() && styles.contains(viewers.front()->getStyle())) { if (!viewers.empty() && styles.contains(viewers.front()->getStyle())) {
// already using these styles // already using these styles
return; return;
...@@ -119,6 +124,13 @@ void DataViewer::setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP ...@@ -119,6 +124,13 @@ void DataViewer::setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP
this->stylesheet = stylesheet; this->stylesheet = stylesheet;
// create viewers // create viewers
viewers.clear(); viewers.clear();
addStyles(styles);
if (extra_styles) addStyles(*extra_styles);
// sort viewers by z-index of style
stable_sort(viewers.begin(), viewers.end(), CompareViewer());
onInit();
}
void DataViewer::addStyles(IndexMap<FieldP,StyleP>& styles) {
FOR_EACH(s, styles) { FOR_EACH(s, styles) {
if ((s->visible || s->visible.isScripted()) && if ((s->visible || s->visible.isScripted()) &&
nativeLook() || ( nativeLook() || (
...@@ -129,14 +141,21 @@ void DataViewer::setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP ...@@ -129,14 +141,21 @@ void DataViewer::setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP
if (viewer) viewers.push_back(viewer); if (viewer) viewers.push_back(viewer);
} }
} }
// sort viewers by z-index of style
stable_sort(viewers.begin(), viewers.end(), CompareViewer());
onInit();
} }
void DataViewer::setData(IndexMap<FieldP,ValueP>& values) { void DataViewer::setData(IndexMap<FieldP,ValueP>& values, IndexMap<FieldP,ValueP>* extra_values) {
FOR_EACH(v, viewers) { FOR_EACH(v, viewers) {
v->setValue(values[v->getField()]); // is this field contained in values?
ValueP val = values.tryGet(v->getField());
if (val) {
v->setValue(val);
} else {
// if it is not in values it should be in extra values
assert(extra_values);
val = extra_values->tryGet(v->getField());
assert(val);
v->setValue(val);
}
} }
onChange(); onChange();
} }
......
...@@ -72,11 +72,14 @@ class DataViewer : public SetView { ...@@ -72,11 +72,14 @@ class DataViewer : public SetView {
virtual void onChangeSet(); virtual void onChangeSet();
// --------------------------------------------------- : The viewers // --------------------------------------------------- : The viewers
private:
/// Create some viewers for the given styles
void addStyles(IndexMap<FieldP,StyleP>& styles);
protected: protected:
/// Set the styles for the data to be shown, recreating the viewers /// Set the styles for the data to be shown, recreating the viewers
void setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP>& styles); void setStyles(const StyleSheetP& stylesheet, IndexMap<FieldP,StyleP>& styles, IndexMap<FieldP,StyleP>* extra_styles = nullptr);
/// Set the data to be shown in the viewers, refresh them /// Set the data to be shown in the viewers, refresh them
void setData(IndexMap<FieldP,ValueP>& values); void setData(IndexMap<FieldP,ValueP>& values, IndexMap<FieldP,ValueP>* extra_values = nullptr);
/// Create a viewer for the given style. /// Create a viewer for the given style.
/** Can be overloaded to create a ValueEditor instead */ /** Can be overloaded to create a ValueEditor instead */
......
...@@ -19,6 +19,7 @@ enum DependencyType ...@@ -19,6 +19,7 @@ enum DependencyType
, DEP_CARDS_FIELD ///< dependency of a script in a "card" field for all cards , DEP_CARDS_FIELD ///< dependency of a script in a "card" field for all cards
, DEP_SET_FIELD ///< dependency of a script in a "set" field , DEP_SET_FIELD ///< dependency of a script in a "set" field
, DEP_STYLE ///< dependency of a script in a "style" property, data gives the stylesheet , DEP_STYLE ///< dependency of a script in a "style" property, data gives the stylesheet
, DEP_EXTRA_CARD_FIELD ///< dependency of a script in an extra stylesheet specific card field
, DEP_CARD_COPY_DEP ///< copy the dependencies from a card field , DEP_CARD_COPY_DEP ///< copy the dependencies from a card field
, DEP_SET_COPY_DEP ///< copy the dependencies from a set field , DEP_SET_COPY_DEP ///< copy the dependencies from a set field
}; };
......
...@@ -123,6 +123,10 @@ void SetScriptManager::initDependencies(Context& ctx, Game& game) { ...@@ -123,6 +123,10 @@ void SetScriptManager::initDependencies(Context& ctx, Game& game) {
void SetScriptManager::initDependencies(Context& ctx, StyleSheet& stylesheet) { void SetScriptManager::initDependencies(Context& ctx, StyleSheet& stylesheet) {
if (stylesheet.dependencies_initialized) return; if (stylesheet.dependencies_initialized) return;
stylesheet.dependencies_initialized = true; stylesheet.dependencies_initialized = true;
// find dependencies of extra card fields
/*FOR_EACH(f, stylesheet.extra_card_fields) {
f->initDependencies(ctx, Dependency(DEP_EXTRA_CARD_FIELD, f->index, &stylesheet));
}*/
// find dependencies of choice images and other style stuff // find dependencies of choice images and other style stuff
FOR_EACH(s, stylesheet.card_style) { FOR_EACH(s, stylesheet.card_style) {
s->initDependencies(ctx, Dependency(DEP_STYLE, s->fieldP->index, &stylesheet)); s->initDependencies(ctx, Dependency(DEP_STYLE, s->fieldP->index, &stylesheet));
...@@ -188,11 +192,20 @@ void SetScriptManager::onAction(const Action& action, bool undone) { ...@@ -188,11 +192,20 @@ void SetScriptManager::onAction(const Action& action, bool undone) {
} }
void SetScriptManager::updateStyles(const CardP& card) { void SetScriptManager::updateStyles(const CardP& card) {
// lastUpdatedCard = card; assert(card);
const StyleSheet& stylesheet = set.stylesheetFor(card); const StyleSheet& stylesheet = set.stylesheetFor(card);
Context& ctx = getContext(card); Context& ctx = getContext(card);
// update extra card fields
card->extra_data.init(stylesheet.extra_card_fields);
FOR_EACH(v, card->extra_data) {
v->update(ctx);
}
// update all styles // update all styles
FOR_EACH_CONST(s, stylesheet.card_style) { updateStyles(ctx, stylesheet.card_style);
updateStyles(ctx, stylesheet.extra_card_style);
}
void SetScriptManager::updateStyles(Context& ctx, const IndexMap<FieldP,StyleP>& styles) {
FOR_EACH_CONST(s, styles) {
if (s->update(ctx)) { if (s->update(ctx)) {
// style has changed, tell listeners // style has changed, tell listeners
s->tellListeners(); s->tellListeners();
...@@ -313,6 +326,17 @@ void SetScriptManager::alsoUpdate(deque<ToUpdate>& to_update, const vector<Depen ...@@ -313,6 +326,17 @@ void SetScriptManager::alsoUpdate(deque<ToUpdate>& to_update, const vector<Depen
ScriptStyleEvent change(stylesheet, style.get()); ScriptStyleEvent change(stylesheet, style.get());
set.actions.tellListeners(change, false); set.actions.tellListeners(change, false);
break; break;
/*} case DEP_EXTRA_CARD_FIELD: {
// Not needed, extra card fields are handled in updateStyles()
if (card) {
StyleSheet* stylesheet = reinterpret_cast<StyleSheet*>(d.data);
StyleSheet* stylesheet_card = &set.stylesheetFor(card);
if (stylesheet == stylesheet_card) {
ValueP value = card->extra_data.at(d.index);
to_update.push_back(ToUpdate(value.get(), card));
}
}
break;*/
} case DEP_CARD_COPY_DEP: { } case DEP_CARD_COPY_DEP: {
// propagate dependencies from another field // propagate dependencies from another field
FieldP f = set.game->card_fields[d.index]; FieldP f = set.game->card_fields[d.index];
......
...@@ -21,6 +21,8 @@ class Value; ...@@ -21,6 +21,8 @@ class Value;
DECLARE_POINTER_TYPE(Game); DECLARE_POINTER_TYPE(Game);
DECLARE_POINTER_TYPE(StyleSheet); DECLARE_POINTER_TYPE(StyleSheet);
DECLARE_POINTER_TYPE(Card); DECLARE_POINTER_TYPE(Card);
DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Style);
// ----------------------------------------------------------------------------- : SetScriptContext // ----------------------------------------------------------------------------- : SetScriptContext
...@@ -76,6 +78,8 @@ class SetScriptManager : public SetScriptContext, public ActionListener { ...@@ -76,6 +78,8 @@ class SetScriptManager : public SetScriptContext, public ActionListener {
void initDependencies(Context&, Game&); void initDependencies(Context&, Game&);
void initDependencies(Context&, StyleSheet&); void initDependencies(Context&, StyleSheet&);
/// Update a map of styles
void updateStyles(Context& ctx, const IndexMap<FieldP,StyleP>& styles);
/// Updates scripts, starting at some value /// Updates scripts, starting at some value
/** if the value changes any dependend values are updated as well */ /** if the value changes any dependend values are updated as well */
void updateValue(Value& value, const CardP& card); void updateValue(Value& value, const CardP& card);
......
...@@ -55,10 +55,12 @@ vector<String> previous_errors; ...@@ -55,10 +55,12 @@ vector<String> previous_errors;
String pending_errors; String pending_errors;
String pending_warnings; String pending_warnings;
DECLARE_TYPEOF_COLLECTION(String); DECLARE_TYPEOF_COLLECTION(String);
wxCriticalSection crit_error_handling;
void handle_error(const String& e, bool allow_duplicate = true, bool now = true) { void handle_error(const String& e, bool allow_duplicate = true, bool now = true) {
// Thread safety
wxCriticalSectionLocker lock(crit_error_handling);
// Check duplicates // Check duplicates
// TODO: thread safety
if (!allow_duplicate) { if (!allow_duplicate) {
FOR_EACH(pe, previous_errors) { FOR_EACH(pe, previous_errors) {
if (e == pe) return; if (e == pe) return;
......
...@@ -26,12 +26,12 @@ ...@@ -26,12 +26,12 @@
#define DECLARE_TYPEOF_COLLECTION(T) #define DECLARE_TYPEOF_COLLECTION(T)
#define TYPEOF(Value) __typeof(Value) #define TYPEOF(Value) __typeof(Value)
#define TYPEOF_IT(Value) __typeof(Value.begin()) #define TYPEOF_IT(Value) __typeof((Value).begin())
#define TYPEOF_CIT(Value) __typeof(Value.begin()) #define TYPEOF_CIT(Value) __typeof((Value).begin())
#define TYPEOF_RIT(Value) __typeof(Value.rbegin()) #define TYPEOF_RIT(Value) __typeof((Value).rbegin())
#define TYPEOF_CRIT(Value) __typeof(Value.rbegin()) #define TYPEOF_CRIT(Value) __typeof((Value).rbegin())
#define TYPEOF_REF(Value) __typeof(*Value.begin())& #define TYPEOF_REF(Value) __typeof(*(Value).begin())&
#define TYPEOF_CREF(Value) __typeof(*Value.begin())& #define TYPEOF_CREF(Value) __typeof(*(Value).begin())&
#else #else
/// Helper for typeof tricks /// Helper for typeof tricks
......
...@@ -43,8 +43,8 @@ class IndexMap : private vector<Value> { ...@@ -43,8 +43,8 @@ class IndexMap : private vector<Value> {
/// Initialize this map with default values given a list of keys /// Initialize this map with default values given a list of keys
/** has no effect if already initialized with the given keys */ /** has no effect if already initialized with the given keys */
void init(const vector<Key>& keys) { bool init(const vector<Key>& keys) {
if (this->size() == keys.size()) return; if (this->size() == keys.size() && (this->empty() || get_key(this->front()) == keys.front())) return false;
this->reserve(keys.size()); this->reserve(keys.size());
for(typename vector<Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it) { for(typename vector<Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it) {
const Key& key = *it; const Key& key = *it;
...@@ -52,6 +52,7 @@ class IndexMap : private vector<Value> { ...@@ -52,6 +52,7 @@ class IndexMap : private vector<Value> {
if (key->index >= this->size()) this->resize(key->index + 1); if (key->index >= this->size()) this->resize(key->index + 1);
init_object(key, (*this)[key->index]); init_object(key, (*this)[key->index]);
} }
return true;
} }
/// Initialize this map with cloned values from another list /// Initialize this map with cloned values from another list
void cloneFrom(const IndexMap<Key,Value>& values) { void cloneFrom(const IndexMap<Key,Value>& values) {
...@@ -75,6 +76,14 @@ class IndexMap : private vector<Value> { ...@@ -75,6 +76,14 @@ class IndexMap : private vector<Value> {
assert(this->size() > key->index); assert(this->size() > key->index);
return at(key->index); return at(key->index);
} }
/// Retrieve a value given its key, if it matches
inline Value tryGet (const Key& key) {
assert(key);
if (this->size() <= key->index) return Value();
Value v = at(key->index);
if (get_key(v) != key) return Value();
return v;
}
/// Is a value contained in this index map? /// Is a value contained in this index map?
inline bool contains(const Value& value) const { inline bool contains(const Value& value) const {
......
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