Commit 51472692 authored by miller86's avatar miller86

2.12RC->Trunk: GUI performance fixes for large dbs

git-svn-id: http://visit.ilight.com/svn/visit/trunk/src@31036 18c085ea-50e0-402c-830e-de6fd14e8384
parent 4e1ceb04
......@@ -5938,7 +5938,7 @@ avtDatabaseMetaData::DetermineVarType(std::string var_in, bool do_expr) const
if (do_expr)
{
ParsingExprList *pel = ParsingExprList::Instance();
Expression *e = pel->GetExpression(var_in);
Expression const *e = pel->GetExpression(var_in);
if (e != NULL)
return ExprType_To_avtVarType(e->GetType());
}
......@@ -7049,7 +7049,7 @@ bool avtDatabaseMetaData::haveWarningCallback = false;
// ****************************************************************************
void
avtDatabaseMetaData::IssueWarning(const char *msg)
avtDatabaseMetaData::IssueWarning(const char *msg) const
{
if (haveWarningCallback)
{
......@@ -7474,3 +7474,71 @@ avtDatabaseMetaData::AddGhostZoneTypePresent(std::string name,
}
}
// ****************************************************************************
// Method: avtDatabaseMetaData::GetTotalVarCount
//
// Purpose: Compute the total number of variables this database has
//
// Programmer: Mark C. Miller, Thu May 25 19:52:38 PDT 2017
//
// ****************************************************************************
int
avtDatabaseMetaData::GetTotalVarCount(void) const
{
return GetNumMeshes() +
GetNumSubsets() +
GetNumScalars() +
GetNumVectors() +
GetNumTensors() +
GetNumSymmTensors() +
GetNumArrays() +
GetNumMaterials() +
GetNumSpecies() +
GetNumCurves() +
GetNumLabels() +
GetNumberOfExpressions();
}
char const *
avtDatabaseMetaData::GetSEGEnvVarName() const
{
return "VISIT_FORCE_SPECULATIVE_EXPRESSION_GENERATION";
}
char const *
avtDatabaseMetaData::GetSEGWarningString() const
{
static char msg[2048];
SNPRINTF(msg, sizeof(msg),
"Due to the large number of variables, %d, in this database, VisIt has\n"
"automatically disabled speculative expression generation of ALL forms\n"
"(e.g. vector-magnitude, mesh-quality, time-derivative, operator-created)\n"
"because the large number of expressions bogs down GUI performance.\n"
"You may override this behavior by exiting VisIt and restarting with the\n"
"environment variable...\n"
" \"%s\"\n"
"set. Be aware that doing so will likely result in sluggish GUI performance.\n"
"If you need one or more of the expressions VisIt's speculative expression\n"
"generation process provides and are unwilling or unable to manually create\n"
"the expression(s) you need, you have no choice in this version of VisIt\n"
"except to override this behavior and suffer any GUI performance issues.\n"
"Unfortunately, if you are running in client-server mode, you will have to\n"
"take action to set this enviornment variable on both the server and client\n"
"machines. This will only be necessary in VisIt version 2.12.3. An entirely\n"
"different mechanism for controlling this behavior will be introduced in 2.13.",
GetTotalVarCount(), GetSEGEnvVarName());
return msg;
}
void
avtDatabaseMetaData::IssueSEGWarningMessage() const
{
IssueWarning(GetSEGWarningString());
}
bool
avtDatabaseMetaData::ShouldDisableSEG(bool envOverride) const
{
return GetTotalVarCount() > 1000 && !envOverride;
}
......@@ -3865,3 +3865,125 @@ avtDatabaseMetaData::AddGhostZoneTypePresent(std::string name,
}
}
Function: GetTotalVarCount
Declaration: int GetTotalVarCount(void) const;
Definition:
// ****************************************************************************
// Method: avtDatabaseMetaData::GetTotalVarCount
//
// Purpose: Compute the total number of variables this database has
//
// Programmer: Mark C. Miller, Thu May 25 19:52:38 PDT 2017
//
// ****************************************************************************
int
avtDatabaseMetaData::GetTotalVarCount(void) const
{
return GetNumMeshes() +
GetNumSubsets() +
GetNumScalars() +
GetNumVectors() +
GetNumTensors() +
GetNumSymmTensors() +
GetNumArrays() +
GetNumMaterials() +
GetNumSpecies() +
GetNumCurves() +
GetNumLabels() +
GetNumberOfExpressions();
}
Function: GetSEGEnvVarName
Declaration: char const *GetSEGEnvVarName(void) const;
Definition:
// ****************************************************************************
// Method: avtDatabaseMetaData::GetSEGEnvVarName
//
// Purpose: Return name of environment variable used to force speculative
// expression generation (SEG).
//
// Programmer: Mark C. Miller, Thu May 25 19:52:38 PDT 2017
//
// ****************************************************************************
char const *
avtDatabaseMetaData::GetSEGEnvVarName(void) const
{
return "VISIT_FORCE_SPECULATIVE_EXPRESSION_GENERATION";
}
Function: GetSEGWarningString
Declaration: char const *GetSEGWarningString(void) const;
Definition:
// ****************************************************************************
// Method: avtDatabaseMetaData::GetSEGWarningString
//
// Purpose: Return warning string regarding disablement of SEG.
//
// Programmer: Mark C. Miller, Thu May 25 19:52:38 PDT 2017
//
// ****************************************************************************
char const *
avtDatabaseMetaData::GetSEGWarningString() const
{
static char msg[2048];
SNPRINTF(msg, sizeof(msg),
"Due to the large number of variables, %d, in this database, VisIt has\n"
"automatically disabled speculative expression generation of ALL forms\n"
"(e.g. vector-magnitude, mesh-quality, time-derivative, operator-created)\n"
"because the large number of expressions bogs down GUI performance.\n"
"You may override this behavior by exiting VisIt and restarting with the\n"
"environment variable...\n"
" \"%s\"\n"
"set. Be aware that doing so will likely result in sluggish GUI performance.\n"
"If you need one or more of the expressions VisIt's speculative expression\n"
"generation process provides and are unwilling or unable to manually create\n"
"the expression(s) you need, you have no choice in this version of VisIt\n"
"except to override this behavior and suffer any GUI performance issues.\n"
"Unfortunately, if you are running in client-server mode, you will have to\n"
"take action to set this enviornment variable on both the server and client\n"
"machines. This will only be necessary in VisIt version 2.12.3. An entirely\n"
"different mechanism for controlling this behavior will be introduced in 2.13.",
GetTotalVarCount(), GetSEGEnvVarName());
return msg;
}
Function: IssueSEGWarningMessage
Declaration: char const *IssueSEGWarningMessage(void) const;
Definition:
// ****************************************************************************
// Method: avtDatabaseMetaData::IssueSEGWarningMessage
//
// Purpose: Use IssueWarning method to issue a warning regarding disablement
// of SEG.
//
// Programmer: Mark C. Miller, Thu May 25 19:52:38 PDT 2017
//
// ****************************************************************************
void
avtDatabaseMetaData::IssueSEGWarningMessage() const
{
IssueWarning(GetSEGWarningString());
}
Function: ShouldDisableSEG
Declaration: bool ShouldDisableSEG(bool envOverride) const;
Definition:
// ****************************************************************************
// Method: avtDatabaseMetaData::ShouldDisableSEG
//
// Purpose: Determine if SEG should be disabled based on TotalVarCount and
// on whether or not the enviornment variable required to override it
// has been set.
//
// Programmer: Mark C. Miller, Thu May 25 19:52:38 PDT 2017
//
// ****************************************************************************
bool
avtDatabaseMetaData::ShouldDisableSEG(bool envOverride) const
{
return GetTotalVarCount() > 1000 && !envOverride;
}
......@@ -394,7 +394,7 @@ public:
void RegisterWarningCallback(void (*)(const char *));
static void (*WarningCallback)(const char *);
static bool haveWarningCallback;
void IssueWarning(const char *msg);
void IssueWarning(const char *msg) const;
bool VarIsCompound(const std::string &inVar) const;
void ParseCompoundForVar(const std::string &inVar, std::string &outVar) const;
void ParseCompoundForMesh(const std::string &inVar, std::string &meshName) const;
......@@ -410,6 +410,11 @@ public:
int GetGhostZoneTypesPresent(std::string name) const;
void ClearGhostTypesPresent(std::string name);
void AddGhostZoneTypePresent(std::string name, avtGhostsZonesPresent v);
int GetTotalVarCount(void) const;
char const * GetSEGEnvVarName() const;
char const * GetSEGWarningString() const;
void IssueSEGWarningMessage() const;
bool ShouldDisableSEG(bool envOverride=false) const;
// IDs that can be used to identify fields in case statements
enum {
......
......@@ -266,6 +266,16 @@
</Function>
<Function name="AddGhostZoneTypePresent" user="true" member="true">
</Function>
<Function name="GetTotalVarCount" user="true" member="true">
</Function>
<Function name="GetSEGEnvVarName" user="true" member="true">
</Function>
<Function name="GetSEGWarningString" user="true" member="true">
</Function>
<Function name="IssueSEGWarningMessage" user="true" member="true">
</Function>
<Function name="ShouldDisableSEG" user="true" member="true">
</Function>
<Include file="header" quoted="false">
Expression.h
</Include>
......
......@@ -67,6 +67,7 @@
#include <avtSIL.h>
#include <DebugStream.h>
#include <Environment.h>
#include <ImproperUseException.h>
#include <InvalidFilesException.h>
#include <InvalidDimensionsException.h>
......@@ -1291,6 +1292,9 @@ avtDatabase::GetMostRecentTimestep(void) const
// Brad Whitlock, Thu Jun 19 10:36:38 PDT 2014
// Removed code to get IO info.
//
// Mark C. Miller, Thu Jun 8 14:14:48 PDT 2017
// Add logic to disable speculative expression generation (SEG) under
// certain conditions.
// ****************************************************************************
void
......@@ -1317,14 +1321,21 @@ avtDatabase::GetNewMetaData(int timeState, bool forceReadAllCyclesTimes)
md->SetMustRepopulateOnStateChange(!MetaDataIsInvariant() ||
!SILIsInvariant());
if (avtDatabaseFactory::GetCreateMeshQualityExpressions())
AddMeshQualityExpressions(md);
if (md->ShouldDisableSEG(Environment::exists(md->GetSEGEnvVarName())))
{
md->IssueSEGWarningMessage();
}
else
{
if (avtDatabaseFactory::GetCreateMeshQualityExpressions())
AddMeshQualityExpressions(md);
if (avtDatabaseFactory::GetCreateTimeDerivativeExpressions())
AddTimeDerivativeExpressions(md);
if (avtDatabaseFactory::GetCreateTimeDerivativeExpressions())
AddTimeDerivativeExpressions(md);
if (avtDatabaseFactory::GetCreateVectorMagnitudeExpressions())
AddVectorMagnitudeExpressions(md);
if (avtDatabaseFactory::GetCreateVectorMagnitudeExpressions())
AddVectorMagnitudeExpressions(md);
}
Convert1DVarMDsToCurveMDs(md);
......@@ -1461,6 +1472,8 @@ avtDatabase::Convert1DVarMDsToCurveMDs(avtDatabaseMetaData *md)
// Matthew Wheeler, Mon 20 May 12:00:00 GMT 2013
// Added min_corner_area and min_sin_corner
//
// Mark C. Miller, Thu Jun 8 14:15:28 PDT 2017
// Skip invalid variables too
// ****************************************************************************
void
......@@ -1496,7 +1509,7 @@ avtDatabase::AddMeshQualityExpressions(avtDatabaseMetaData *md)
if (topoDim == 0 || topoDim == 1)
continue;
if (mmd->hideFromGUI)
if (mmd->hideFromGUI || !mmd->validVariable)
continue;
int pass_for_this_mesh = 2;
......@@ -1600,6 +1613,8 @@ avtDatabase::AddMeshQualityExpressions(avtDatabaseMetaData *md)
// Variable names may be compound (eg "mesh/ireg") so make sure they are
// enclosed in angle-brackets at the beginning of the created expression.
//
// Mark C. Miller, Thu Jun 8 14:15:50 PDT 2017
// Skip invalid variables too
// ****************************************************************************
void
......@@ -1617,6 +1632,9 @@ avtDatabase::AddTimeDerivativeExpressions(avtDatabaseMetaData *md)
{
const avtMeshMetaData *mmd = md->GetMesh(i);
if (mmd->hideFromGUI || !mmd->validVariable)
continue;
string base2;
if (numMeshes == 1)
base2 = base1;
......@@ -1823,20 +1841,27 @@ avtDatabase::AddTimeDerivativeExpressions(avtDatabaseMetaData *md)
//
// Mark C. Miller, Tue Apr 15 15:12:26 PDT 2008
// Eliminated database objects for which hideFromGUI is true
//
// Mark C. Miller, Thu Jun 8 14:16:27 PDT 2017
// Skip invalid variables too. Const qualified md pointer and expressions.
// ****************************************************************************
void
avtDatabase::AddVectorMagnitudeExpressions(avtDatabaseMetaData *md)
{
avtDatabaseMetaData const *const_md = md;
char buff[1024];
// get vectors from database metadata
int nvectors = md->GetNumVectors();
for(int i=0; i < nvectors; ++i)
{
if (md->GetVectors(i).hideFromGUI)
avtVectorMetaData const &vmd = const_md->GetVectors(i);
if (vmd.hideFromGUI || !vmd.validVariable)
continue;
const char *vec_name = md->GetVectors(i).name.c_str();
const char *vec_name = vmd.name.c_str();
Expression new_expr;
SNPRINTF(buff,1024, "%s_magnitude", vec_name);
new_expr.SetName(buff);
......@@ -1848,7 +1873,7 @@ avtDatabase::AddVectorMagnitudeExpressions(avtDatabaseMetaData *md)
}
// also get any from database expressions
ExpressionList elist = md->GetExprList();
ExpressionList const elist = md->GetExprList();
int nexprs = elist.GetNumExpressions();
for(int i=0; i < nexprs; ++i)
{
......
......@@ -867,7 +867,7 @@ avtExpressionFilter::DetermineVariableType(std::string &varname)
// Note: due to the way that the pipeline is constructed by the EEF,
// I'm not sure if this case will ever occur.
//
Expression *exp = ParsingExprList::GetExpression(varname.c_str());
Expression const *exp = ParsingExprList::GetExpression(varname.c_str());
if (exp != NULL)
return ExprType_To_avtVarType(exp->GetType());
......
......@@ -149,7 +149,7 @@ avtMacroExpressionFilter::ReplaceMacroInExpressionList(void)
int num_expr = new_list.GetNumExpressions();
for (int i = num_expr-1 ; i >= 0 ; i--)
{
Expression &expr = new_list.GetExpressions(i);
Expression const &expr = new_list.GetExpressions(i);
if (expr.GetName() == outputVariableName)
{
new_list.RemoveExpressions(i);
......
......@@ -282,7 +282,7 @@ avtExpressionEvaluatorFilter::VerifyVariableTypes(void)
{
const std::string &varname = atts.GetVariableName(i);
avtVarType vt = atts.GetVariableType(varname.c_str());
Expression *exp = ParsingExprList::GetExpression(varname.c_str());
Expression const *exp = ParsingExprList::GetExpression(varname.c_str());
if (exp == NULL)
continue;
Expression::ExprType et = exp->GetType();
......@@ -498,7 +498,7 @@ avtExpressionEvaluatorFilter::ModifyContract(avtContract_p spec)
}
// Check if this is an expression, a real variable, or a data binning.
Expression *exp = ParsingExprList::GetExpression(var);
Expression const *exp = ParsingExprList::GetExpression(var);
avtDataBinning *db = NULL;
if (getDataBinningCallback != NULL)
db = getDataBinningCallback(getDataBinningCallbackArgs, var.c_str());
......
......@@ -346,8 +346,8 @@ avtTimeIteratorExpression::Execute(void)
void
avtTimeIteratorExpression::UpdateExpressions(int ts)
{
ParsingExprList *pel = ParsingExprList::Instance();
ExpressionList new_list = *(pel->GetList());
ExpressionList const *curExprList = ParsingExprList::Instance()->GetList();
ExpressionList addExprs;
int nvars = (int)varnames.size();
if (cmfeType == POS_CMFE)
......@@ -376,26 +376,19 @@ avtTimeIteratorExpression::UpdateExpressions(int ts)
std::string exp_name = GetInternalVarname(i);
bool alreadyInList = false;
for (int j = 0 ; j < new_list.GetNumExpressions() ; j++)
{
if (new_list[j].GetName() == exp_name)
{
alreadyInList = true;
new_list[j].SetDefinition(expr_defn);
}
}
bool alreadyInList = curExprList->operator[](exp_name.c_str());
if (!alreadyInList)
{
Expression exp;
exp.SetName(exp_name);
exp.SetDefinition(expr_defn);
exp.SetType(Expression::Unknown);
new_list.AddExpressions(exp);
addExprs.AddExpressions(exp);
}
}
*(pel->GetList()) = new_list;
for (int i = 0; i < addExprs.GetNumExpressions(); i++)
ParsingExprList::Instance()->GetList()->AddExpressions(addExprs.GetExpressions(i));
}
......
......@@ -182,7 +182,7 @@ ParsingExprList::Update(Subject *)
// Modifications:
//
// ****************************************************************************
Expression*
Expression const *
ParsingExprList::GetExpression(const char *varname)
{
return Instance()->GetList()->operator[](varname);
......@@ -218,7 +218,7 @@ ParsingExprList::GetExpressionTree(const char *varname)
// Get the expression tree for the expression.
//Expression *exp = const_cast<ExpressionList&>(exprList)[varname];
Expression *exp = GetExpression(varname);
Expression const *exp = GetExpression(varname);
if (exp != NULL)
{
ParseTreeNode *t=Instance()->GetParser()->Parse(exp->GetDefinition());
......@@ -252,7 +252,7 @@ ParsingExprList::GetExpressionTree(const char *varname)
//
// ****************************************************************************
ExprNode *
ParsingExprList::GetExpressionTree(Expression *expr)
ParsingExprList::GetExpressionTree(Expression const *expr)
{
if (!expr)
return NULL;
......@@ -304,7 +304,7 @@ GetRealVariableHelper(const string &var, set<string> expandedVars)
expandedVars.insert(var);
// If this variable is not an expression, then it is real
Expression *expr = ParsingExprList::GetExpression(var);
Expression const *expr = ParsingExprList::GetExpression(var);
if (!expr)
{
// Found the real variable
......
......@@ -86,15 +86,15 @@ public:
~ParsingExprList();
static ParsingExprList *Instance();
static Expression* GetExpression(const char *varname);
static Expression* GetExpression(std::string varname)
static Expression const * GetExpression(const char *varname);
static Expression const * GetExpression(std::string varname)
{ return GetExpression(varname.c_str()); }
ExpressionList *GetList() {return &exprList;}
virtual void Update(Subject *);
static ExprNode *GetExpressionTree(Expression*);
static ExprNode *GetExpressionTree(Expression const *);
static ExprNode *GetExpressionTree(const char *varname);
static ExprNode *GetExpressionTree(std::string varname)
{ return GetExpressionTree(varname.c_str()); }
......
......@@ -75,4 +75,6 @@ namespace DebugStream
#define debug4 if (!DebugStream::Level4()) ; else (DebugStream::Stream4())
#define debug5 if (!DebugStream::Level5()) ; else (DebugStream::Stream5())
#define vcerr(c) if (VisItInit::IsComponent(#c)) std::cerr << #c ": "
#endif
......@@ -452,6 +452,8 @@ VisItInit::Initialize(int &argc, char *argv[], int r, int n, bool strip, bool si
if(enableTimings)
visitTimer->Enable();
atexit(VisItInit::Finalize);
#if !defined(_WIN32)
std::set_new_handler(NewHandler);
#endif
......
......@@ -157,7 +157,7 @@ class PLUGIN_API CommonOperatorPluginInfo : public virtual GeneralOperatorPlugin
virtual AttributeSubject *AllocAttributes() = 0;
virtual void CopyAttributes(AttributeSubject *to,
AttributeSubject *from) = 0;
virtual ExpressionList *GetCreatedExpressions(const avtDatabaseMetaData *) {return NULL;}
virtual ExpressionList *GetCreatedExpressions(const avtDatabaseMetaData *) const {return NULL;}
virtual bool GetUserSelectable() const { return true; }
virtual int GetVariableTypes() const { return 0; }
virtual int GetVariableMask() const { return ~0; }
......
......@@ -36,10 +36,14 @@
*
*****************************************************************************/
#include <BJHash.h>
#include <ExpressionList.h>
#include <DataNode.h>
#include <Expression.h>
#include <algorithm>
#include <vector>
// ****************************************************************************
// Method: ExpressionList::ExpressionList
//
......@@ -57,7 +61,8 @@
void ExpressionList::Init()
{
sortedNameHashNeedsSorting = true;
myHashVal = 0;
ExpressionList::SelectAll();
}
......@@ -94,7 +99,8 @@ void ExpressionList::Copy(const ExpressionList &obj)
Expression *newExpression = new Expression(*oldExpression);
expressions.push_back(newExpression);
}
sortedNameHashNeedsSorting = true;
myHashVal = 0;
ExpressionList::SelectAll();
}
......@@ -255,17 +261,7 @@ ExpressionList::operator = (const ExpressionList &obj)
bool
ExpressionList::operator == (const ExpressionList &obj) const
{
bool expressions_equal = (obj.expressions.size() == expressions.size());
for(size_t i = 0; (i < expressions.size()) && expressions_equal; ++i)
{
// Make references to Expression from AttributeGroup *.
const Expression &expressions1 = *((const Expression *)(expressions[i]));
const Expression &expressions2 = *((const Expression *)(obj.expressions[i]));
expressions_equal = (expressions1 == expressions2);
}
// Create the return value
return (expressions_equal);
return GetHashVal() == obj.GetHashVal();
}
// ****************************************************************************
......@@ -592,6 +588,8 @@ ExpressionList::AddExpressions(const Expression &obj)
{
Expression *newExpression = new Expression(obj);
expressions.push_back(newExpression);
myHashVal = 0;
sortedNameHashNeedsSorting = true;
// Indicate that things have changed by selecting it.
Select(ID_expressions, (void *)&expressions);
......@@ -620,6 +618,9 @@ ExpressionList::ClearExpressions()
for(pos = expressions.begin(); pos != expressions.end(); ++pos)
delete *pos;
expressions.clear();
sortedNameHash.clear();
sortedNameHashNeedsSorting = true;
myHashVal = 0;
// Indicate that things have changed by selecting the list.
Select(ID_expressions, (void *)&expressions);
......@@ -643,17 +644,23 @@ ExpressionList::ClearExpressions()
void
ExpressionList::RemoveExpressions(int index)
{
AttributeGroupVector::iterator pos = expressions.begin();
AttributeGroupVector::iterator pos = expressions.begin() + index;
// Iterate through the vector "index" times.
for(int i = 0; i < index; ++i)
if(pos != expressions.end()) ++pos;
// If pos is still a valid iterator, remove that element.
if(pos != expressions.end())
if ((size_t) index < expressions.size() && pos != expressions.end())
{
delete *pos;
expressions.erase(pos);
for (std::vector<std::pair<unsigned int,size_t> >::iterator i =
sortedNameHash.begin(); i != sortedNameHash.end(); ++i)
{
if (i->second == index)
{
sortedNameHash.erase(i);
break;
}
}
myHashVal = 0;
sortedNameHashNeedsSorting = true;
}
// Indicate that things have changed by selecting the list.
......@@ -699,6 +706,8 @@ ExpressionList::GetNumExpressions() const
Expression &
ExpressionList::GetExpressions(int i)
{
myHashVal = 0;
sortedNameHashNeedsSorting = true;
return *((Expression *)expressions[i]);
}
......@@ -741,6 +750,8 @@ ExpressionList::GetExpressions(int i) const
Expression &
ExpressionList::operator [] (int i)
{
myHashVal = 0;
sortedNameHashNeedsSorting = true;
return *((Expression *)expressions[i]);
}
......@@ -889,19 +900,89 @@ ExpressionList::FieldsEqual(int index_, const AttributeGroup *rhs) const
///////////////////////////////////////////////////////////////////////////////
// User-defined methods.
///////////////////////////////////////////////////////////////////////////////
static bool compNameHashPairs(std::pair<unsigned int, size_t> const &a,
std::pair<unsigned int, size_t> const &b)
{
return a.first < b.first;
}
void ExpressionList::SortNameHash(void)
{
sortedNameHash.resize(expressions.size());
for (size_t i = 0; i < expressions.size(); i++)
{
Expression const *e = (Expression *) expressions[i];
unsigned int hashval = BJHash::Hash(e->GetName());
sortedNameHash[i] = std::pair<unsigned int, size_t>(hashval, i);
}
std::sort(sortedNameHash.begin(), sortedNameHash.end(), compNameHashPairs);
sortedNameHashNeedsSorting = false;
}
// Modifications:
// Brad Whitlock, Thu Aug 28 15:29:59 PST 2003
// Simplified and removed dynamic_cast so it works on Windows.
//
Expression*
Expression *
ExpressionList::operator[](const char *varname)
{
// Check to see if there is an expression of this name.
std::string var(varname);
for (int i = 0; i < GetNumExpressions(); ++i)
unsigned int hashval = BJHash::Hash(var);
if (expressions.size() != sortedNameHash.size() || sortedNameHashNeedsSorting)
SortNameHash();
// Binary search to match hash, then linear over entries with same hash val
std::pair