Rename the enums used for flags such that they are more likely unique.
Also a bit of other clean-up to limit the use of the option flags more
into the generic parts. Removed a few unnecessary flags. Made
efClearOnNextSet work more correctly for classes that don't use
OptionStorageTemplate, although currently it didn't cause any issues
(noticed some issues while developing SelectionFileOption, but the final
version worked without these fixes).
Change-Id: I78c243c4f73b87b285eb54d6ff3ae42699678962
maxValueCount_(settings.maxValueCount_),
inSet_(false)
{
- // If the maximum number of values is not known, storage to
- // caller-allocated memory is unsafe.
- if ((maxValueCount_ < 0 || hasFlag(efMulti)) && hasFlag(efExternalStore))
- {
- GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
- }
// Check that user has not provided incorrect values for vectors.
- if (hasFlag(efVector) && (minValueCount_ > 1 || maxValueCount_ < 1))
+ if (hasFlag(efOption_Vector) && (minValueCount_ > 1 || maxValueCount_ < 1))
{
GMX_THROW(APIError("Inconsistent value counts for vector values"));
}
name_ = settings.name_;
}
descr_ = settings.createDescription();
+ setFlag(efOption_ClearOnNextSet);
}
AbstractOptionStorage::~AbstractOptionStorage()
void AbstractOptionStorage::startSource()
{
- setFlag(efClearOnNextSet);
+ setFlag(efOption_ClearOnNextSet);
}
void AbstractOptionStorage::startSet()
// The last condition takes care of the situation where multiple
// sources are used, and a later source should be able to reassign
// the value even though the option is already set.
- if (isSet() && !hasFlag(efMulti) && !hasFlag(efClearOnNextSet))
+ if (isSet() && !hasFlag(efOption_MultipleTimes)
+ && !hasFlag(efOption_ClearOnNextSet))
{
GMX_THROW(InvalidInputError("Option specified multiple times"));
}
{
GMX_RELEASE_ASSERT(inSet_, "startSet() not called");
inSet_ = false;
- // TODO: Should this be done only when processSet() does not throw?
- setFlag(efSet);
+ // TODO: Should this be set or not when processSet() throws?
+ setFlag(efOption_Set);
+ // TODO: Correct handling of the efOption_ClearOnNextSet requires
+ // processSet() and/or convertValue() to check it internally.
+ // OptionStorageTemplate takes care of it, but it's error-prone if
+ // a custom option is implemented that doesn't use it.
processSet();
+ clearFlag(efOption_ClearOnNextSet);
}
void AbstractOptionStorage::finish()
{
GMX_RELEASE_ASSERT(!inSet_, "finishSet() not called");
processAll();
- if (hasFlag(efRequired) && !isSet())
+ if (isRequired() && !isSet())
{
GMX_THROW(InvalidInputError("Option is required, but not set"));
}
void AbstractOptionStorage::setMinValueCount(int count)
{
- GMX_RELEASE_ASSERT(!hasFlag(efMulti),
- "setMinValueCount() not supported with efMulti");
+ GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
+ "setMinValueCount() not supported with efOption_MultipleTimes");
GMX_RELEASE_ASSERT(count >= 0, "Invalid value count");
minValueCount_ = count;
- if (isSet()
- && !hasFlag(efDontCheckMinimumCount) && valueCount() < minValueCount_)
+ if (isSet() && !hasFlag(efOption_DontCheckMinimumCount)
+ && valueCount() < minValueCount_)
{
GMX_THROW(InvalidInputError("Too few values"));
}
void AbstractOptionStorage::setMaxValueCount(int count)
{
- GMX_RELEASE_ASSERT(!hasFlag(efMulti),
- "setMaxValueCount() not supported with efMulti");
+ GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
+ "setMaxValueCount() not supported with efOption_MultipleTimes");
GMX_RELEASE_ASSERT(count >= -1, "Invalid value count");
maxValueCount_ = count;
if (isSet() && maxValueCount_ >= 0 && valueCount() > maxValueCount_)
//! Sets or clears a flag for the option.
void setFlag(OptionFlag flag, bool bSet) { flags_.set(flag, bSet); }
//! Returns true if the option is vector-valued.
- bool isVector() const { return hasFlag(efVector); }
- //! Sets the option to be vector-valued.
+ bool isVector() const { return hasFlag(efOption_Vector); }
+ /*! \brief
+ * Sets the option to be vector-valued.
+ *
+ * This method is provided for convenience to make management of value
+ * counts easier. In order to implement a vector-valued option, the
+ * class derived from AbstractOption should expose a method that calls
+ * this method, and the storage object derived from
+ * AbstractOptionStorage should check isVector().
+ * If only a single value is provided, the storage object should fill
+ * the whole vector with that value.
+ *
+ * The length of the vector (the value of maxValueCount_) must be
+ * fixed. The default length is 3 elements.
+ */
void setVector()
{
- setFlag(efVector);
+ setFlag(efOption_Vector);
minValueCount_ = 1;
if (maxValueCount_ == 1)
{
//! Sets the required number of values for the option.
void setValueCount(int count)
{
- if (!hasFlag(efVector))
+ if (!hasFlag(efOption_Vector))
{
minValueCount_ = count;
}
{ setDescription(descr); return me(); }
//! Hides the option from normal help output.
MyClass &hidden(bool bHidden = true)
- { setFlag(efHidden, bHidden); return me(); }
+ { setFlag(efOption_Hidden, bHidden); return me(); }
//! Requires the option to be specified explicitly.
MyClass &required(bool bRequired = true)
- { setFlag(efRequired, bRequired); return me(); }
+ { setFlag(efOption_Required, bRequired); return me(); }
//! Allows the option to be specified multiple times.
MyClass &allowMultiple(bool bMulti = true)
- { setFlag(efMulti, bMulti); return me(); }
+ { setFlag(efOption_MultipleTimes, bMulti); return me(); }
//! Requires exactly \p count values for the option.
MyClass &valueCount(int count) { setValueCount(count); return me(); }
//! Allows any number of values for the option.
* Options object exists.
*/
MyClass &store(T *store)
- { setFlag(efExternalStore); store_ = store; return me(); }
+ { store_ = store; return me(); }
/*! \brief
* Stores number of values in the value pointed by \p countptr.
*
* Options object exists.
*/
MyClass &storeVector(std::vector<T> *store)
- { setFlag(efExternalValueVector); storeVector_ = store; return me(); }
+ { storeVector_ = store; return me(); }
protected:
/*! \cond libapi */
virtual ~AbstractOptionStorage();
//! Returns true if the option has been set.
- bool isSet() const { return hasFlag(efSet); }
+ bool isSet() const { return hasFlag(efOption_Set); }
/*! \brief
* Returns true if the option is a boolean option.
*
*/
bool isBoolean() const;
//! Returns true if the option is a hidden option.
- bool isHidden() const { return hasFlag(efHidden); }
+ bool isHidden() const { return hasFlag(efOption_Hidden); }
//! Returns true if the option is required.
- bool isRequired() const { return hasFlag(efRequired); }
+ bool isRequired() const { return hasFlag(efOption_Required); }
+ //! Returns true if the option is vector-valued.
+ bool isVector() const { return hasFlag(efOption_Vector); }
//! Returns the name of the option.
const std::string &name() const { return name_; }
//! Returns the description of the option.
AbstractOptionStorage(const AbstractOption &settings,
OptionFlags staticFlags);
+ //! Marks the option as set.
+ void markAsSet() { flags_.set(efOption_Set); }
//! Returns true if the given flag is set.
bool hasFlag(OptionFlag flag) const { return flags_.test(flag); }
//! Sets the given flag.
* If values have already been provided, it is checked that there are
* enough.
*
- * Cannot be called for options with ::efMulti set, because it is
- * impossible to check the requirement after the values have been set.
+ * Cannot be called for options with ::efOption_MultipleTimes set,
+ * because it is impossible to check the requirement after the values
+ * have been set.
* If attempted, will assert.
*/
void setMinValueCount(int count);
* If values have already been provided, it is checked that there are
* not too many.
*
- * Cannot be called for options with ::efMulti set, because it is
- * impossible to check the requirement after the values have been set.
+ * Cannot be called for options with ::efOption_MultipleTimes set,
+ * because it is impossible to check the requirement after the values
+ * have been set.
* If attempted, will assert.
*/
void setMaxValueCount(int count);
void IntegerOptionStorage::processSetValues(ValueList *values)
{
- if (hasFlag(efVector))
+ if (isVector())
{
expandVector(maxValueCount(), values);
}
const char *DoubleOptionStorage::typeString() const
{
- return hasFlag(efVector) ? "vector" : (isTime() ? "time" : "double");
+ return isVector() ? "vector" : (isTime() ? "time" : "double");
}
std::string DoubleOptionStorage::formatSingleValue(const double &value) const
void DoubleOptionStorage::processSetValues(ValueList *values)
{
- if (hasFlag(efVector))
+ if (isVector())
{
expandVector(maxValueCount(), values);
}
void DoubleOptionStorage::setScaleFactor(double factor)
{
GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
- if (!hasFlag(efHasDefaultValue))
+ if (!hasFlag(efOption_HasDefaultValue))
{
double scale = factor / factor_;
ValueList::iterator i;
virtual OptionInfo &optionInfo() { return info_; }
virtual const char *typeString() const
- { return hasFlag(efVector) ? "vector" : "int"; }
+ { return isVector() ? "vector" : "int"; }
virtual std::string formatSingleValue(const int &value) const;
private:
enum OptionFlag
{
//! %Option has been set.
- efSet = 1<<0,
+ efOption_Set = 1<<0,
//! The current value of the option is a programmatic default value.
- efHasDefaultValue = 1<<1,
+ efOption_HasDefaultValue = 1<<1,
/*! \brief
* Next assignment to the option clears old values.
*
* This flag is set when a new option source starts, such that values
* from the new source will overwrite old ones.
*/
- efClearOnNextSet = 1<<5,
+ efOption_ClearOnNextSet = 1<<2,
//! %Option is required to be set.
- efRequired = 1<<2,
+ efOption_Required = 1<<4,
//! %Option can be specified multiple times.
- efMulti = 1<<3,
+ efOption_MultipleTimes = 1<<5,
//! %Option is hidden from standard help.
- efHidden = 1<<4,
+ efOption_Hidden = 1<<6,
/*! \brief
* %Option value is a vector, but a single value is also accepted.
*
- * If only a single value is provided, the storage object should fill the
- * whole vector with that value. The length of the vector must be fixed.
- * The default length is 3 elements.
+ * \see AbstractOption::setVector()
*/
- efVector = 1<<6,
- efExternalStore = 1<<8,
- efExternalValueVector = 1<<10,
+ efOption_Vector = 1<<8,
//! %Option does not support default values.
- efNoDefaultValue = 1<<7,
+ efOption_NoDefaultValue = 1<<9,
/*! \brief
* Storage object does its custom checking for minimum value count.
*
* This is useful to override the default check, which is done in
* OptionStorageTemplate::processSet().
*/
- efDontCheckMinimumCount = 1<<16,
- //efDynamic = 1<<16,
- //efRanges = 1<<17,
- //efEnum = 1<<18,
- //efStaticEnum = 1<<19,
- //efVarNum = 1<<20,
- //efAtomVal = 1<<21,
+ efOption_DontCheckMinimumCount = 1<<10
};
//! \libinternal Holds a combination of ::OptionFlag values.
* \throws APIError if invalid settings have been provided.
*/
template <class U>
- OptionStorageTemplate(const OptionTemplate<T, U> &settings,
- OptionFlags staticFlags = OptionFlags());
+ explicit OptionStorageTemplate(const OptionTemplate<T, U> &settings,
+ OptionFlags staticFlags = OptionFlags());
virtual void clearSet();
store_(settings.store_),
countptr_(settings.countptr_)
{
+ // If the maximum number of values is not known, storage to
+ // caller-allocated memory is unsafe.
+ if (store_ != NULL && (maxValueCount() < 0 || hasFlag(efOption_MultipleTimes)))
+ {
+ GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
+ }
if (values_ == NULL)
{
- // The flag should be set for proper error checking.
- GMX_RELEASE_ASSERT(!hasFlag(efExternalValueVector),
- "Internal inconsistency");
ownedValues_.reset(new std::vector<T>);
values_ = ownedValues_.get();
}
- if (hasFlag(efNoDefaultValue)
+ if (hasFlag(efOption_NoDefaultValue)
&& (settings.defaultValue_ != NULL
|| settings.defaultValueIfSet_ != NULL))
{
GMX_THROW(APIError("Option does not support default value, but one is set"));
}
- if (store_ != NULL && countptr_ == NULL && !hasFlag(efVector)
+ if (store_ != NULL && countptr_ == NULL && !isVector()
&& minValueCount() != maxValueCount())
{
GMX_THROW(APIError("Count storage is not set, although the number of produced values is not known"));
}
- if (!hasFlag(efNoDefaultValue))
+ if (!hasFlag(efOption_NoDefaultValue))
{
- setFlag(efHasDefaultValue);
+ setFlag(efOption_HasDefaultValue);
if (settings.defaultValue_ != NULL)
{
values_->clear();
}
if (settings.defaultValueIfSet_ != NULL)
{
- if (hasFlag(efMulti))
+ if (hasFlag(efOption_MultipleTimes))
{
GMX_THROW(APIError("defaultValueIfSet() is not supported with allowMultiple()"));
}
defaultValueIfSet_.reset(new T(*settings.defaultValueIfSet_));
}
}
- setFlag(efClearOnNextSet);
}
if (setValues_.empty() && defaultValueIfSet_.get() != NULL)
{
addValue(*defaultValueIfSet_);
- setFlag(efHasDefaultValue);
+ setFlag(efOption_HasDefaultValue);
}
else
{
- clearFlag(efHasDefaultValue);
+ clearFlag(efOption_HasDefaultValue);
}
- if (!hasFlag(efDontCheckMinimumCount)
+ if (!hasFlag(efOption_DontCheckMinimumCount)
&& setValues_.size() < static_cast<size_t>(minValueCount()))
{
- clearSet();
GMX_THROW(InvalidInputError("Too few (valid) values"));
}
commitValues();
template <typename T>
void OptionStorageTemplate<T>::commitValues()
{
- if (hasFlag(efClearOnNextSet))
+ if (hasFlag(efOption_ClearOnNextSet))
{
values_->swap(setValues_);
- clearFlag(efClearOnNextSet);
}
else
{
{
addValue("dummy");
}
- /*! \brief
- * Calls setFlag(efSet).
- */
- void setOption()
- {
- setFlag(gmx::efSet);
- }
+ // using MyBase::markAsSet;
// using MyBase::addValue;
// using MyBase::commitValues;
// "using" is correct but MSVC gives error C2248. Workaround:
+ void markAsSet()
+ {
+ MyBase::markAsSet();
+ }
void addValue(const std::string &value)
{
MyBase::addValue(value);
using ::testing::DoAll;
using ::testing::InvokeWithoutArgs;
EXPECT_CALL(*mock, processAll())
- .WillOnce(DoAll(InvokeWithoutArgs(mock, &MockOptionStorage::setOption),
+ .WillOnce(DoAll(InvokeWithoutArgs(mock, &MockOptionStorage::markAsSet),
InvokeWithoutArgs(mock, &MockOptionStorage::addDummyValue),
InvokeWithoutArgs(mock, &MockOptionStorage::commitValues)));
}
int flags = bSelection ? POS_COMPLMAX : POS_COMPLWHOLE;
if (bSelection)
{
- if (sel->hasFlag(gmx::efDynamicMask))
+ if (sel->hasFlag(gmx::efSelection_DynamicMask))
{
flags |= POS_MASKONLY;
}
- if (sel->hasFlag(gmx::efEvaluateVelocities))
+ if (sel->hasFlag(gmx::efSelection_EvaluateVelocities))
{
flags |= POS_VELOCITIES;
}
- if (sel->hasFlag(gmx::efEvaluateForces))
+ if (sel->hasFlag(gmx::efSelection_EvaluateForces))
{
flags |= POS_FORCES;
}
}
posInfo_.push_back(PositionInfo(mass, charge));
}
- if (isDynamic() && !hasFlag(efDynamicMask))
+ if (isDynamic() && !hasFlag(efSelection_DynamicMask))
{
originalPosInfo_ = posInfo_;
}
gmx_ana_pos_t &p = rawPositions_;
gmx_ana_index_copy(p.g, rootElement_->v.u.g, false);
p.g->name = NULL;
- gmx_ana_indexmap_update(&p.m, p.g, hasFlag(gmx::efDynamicMask));
+ gmx_ana_indexmap_update(&p.m, p.g, hasFlag(gmx::efSelection_DynamicMask));
p.nr = p.m.nr;
refreshMassesAndCharges();
}
*/
enum SelectionFlag
{
- efOnlyStatic = 1<<0,
- efOnlyAtoms = 1<<1,
+ efSelection_OnlyStatic = 1<<0,
+ efSelection_OnlyAtoms = 1<<1,
//! Whether ::POS_MASKONLY should be used for output position evaluation.
- efDynamicMask = 1<<2,
- efDynamicOnlyWhole = 1<<3,
+ efSelection_DynamicMask = 1<<2,
+ efSelection_DynamicOnlyWhole = 1<<3,
//! Whether velocities of output positions should be evaluated.
- efEvaluateVelocities = 1<<5,
+ efSelection_EvaluateVelocities = 1<<5,
//! Whether forces on output positions should be evaluated.
- efEvaluateForces = 1<<6,
+ efSelection_EvaluateForces = 1<<6,
};
//! \internal Holds a collection of ::SelectionFlag values.
*/
SelectionOptionStorage::SelectionOptionStorage(const SelectionOption &settings)
- : MyBase(settings, OptionFlags() | efNoDefaultValue | efDontCheckMinimumCount),
+ : MyBase(settings, OptionFlags() | efOption_NoDefaultValue
+ | efOption_DontCheckMinimumCount),
info_(this), manager_(NULL), selectionFlags_(settings.selectionFlags_)
{
- GMX_RELEASE_ASSERT(!hasFlag(efMulti),
+ GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
"allowMultiple() is not supported for selection options");
if (settings.infoPtr_ != NULL)
{
{
// TODO: Having this check in the parser would make interactive input
// behave better.
- if (selectionFlags_.test(efOnlyStatic) && i->isDynamic())
+ if (selectionFlags_.test(efSelection_OnlyStatic) && i->isDynamic())
{
GMX_THROW(InvalidInputError("Dynamic selections not supported"));
}
if (bFullValue)
{
commitValues();
- setFlag(efSet);
+ markAsSet();
}
}
GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
manager_->requestOptionDelayedParsing(this);
- setFlag(efSet);
+ markAsSet();
}
}
errors.startContext("In option '" + name() + "'");
if (count >= 0)
{
- // Should not throw because efDontCheckMinimumCount is set
+ // Should not throw because efOption_DontCheckMinimumCount is set.
setMinValueCount(count);
if (valueCount() > 0 && valueCount() < count)
{
ValueList::iterator i;
for (i = values().begin(); i != values().end(); ++i)
{
- if (flag == efOnlyStatic && bSet && i->isDynamic())
+ if (flag == efSelection_OnlyStatic && bSet && i->isDynamic())
{
MessageStringCollector errors;
errors.startContext("In option '" + name() + "'");
void SelectionOptionInfo::setEvaluateVelocities(bool bEnabled)
{
- option().setSelectionFlag(efEvaluateVelocities, bEnabled);
+ option().setSelectionFlag(efSelection_EvaluateVelocities, bEnabled);
}
void SelectionOptionInfo::setEvaluateForces(bool bEnabled)
{
- option().setSelectionFlag(efEvaluateForces, bEnabled);
+ option().setSelectionFlag(efSelection_EvaluateForces, bEnabled);
}
void SelectionOptionInfo::setOnlyAtoms(bool bEnabled)
{
- option().setSelectionFlag(efOnlyAtoms, bEnabled);
+ option().setSelectionFlag(efSelection_OnlyAtoms, bEnabled);
}
void SelectionOptionInfo::setOnlyStatic(bool bEnabled)
{
- option().setSelectionFlag(efOnlyStatic, bEnabled);
+ option().setSelectionFlag(efSelection_OnlyStatic, bEnabled);
}
void SelectionOptionInfo::setDynamicMask(bool bEnabled)
{
- option().setSelectionFlag(efDynamicMask, bEnabled);
+ option().setSelectionFlag(efSelection_DynamicMask, bEnabled);
}
void SelectionOptionInfo::setDynamicOnlyWhole(bool bEnabled)
{
- option().setSelectionFlag(efDynamicOnlyWhole, bEnabled);
+ option().setSelectionFlag(efSelection_DynamicOnlyWhole, bEnabled);
}
*/
SelectionFileOptionStorage::SelectionFileOptionStorage(const SelectionFileOption &settings)
- : AbstractOptionStorage(settings, OptionFlags() | efMulti | efDontCheckMinimumCount),
+ : AbstractOptionStorage(settings, OptionFlags() | efOption_MultipleTimes
+ | efOption_DontCheckMinimumCount),
info_(this), manager_(NULL), bValueParsed_(false)
{
}
* in which case SelectionPosition::hasVelocity() returns false.
*/
MyClass &evaluateVelocities()
- { selectionFlags_.set(efEvaluateVelocities); return me(); }
+ { selectionFlags_.set(efSelection_EvaluateVelocities); return me(); }
/*! \brief
* Request force evaluation for output positions.
*
* in which case SelectionPosition::hasForce() returns false.
*/
MyClass &evaluateForces()
- { selectionFlags_.set(efEvaluateForces); return me(); }
+ { selectionFlags_.set(efSelection_EvaluateForces); return me(); }
/*! \brief
* Only accept selections that evaluate to atom positions.
*
* TODO: This option is not yet implemented.
*/
MyClass &onlyAtoms()
- { selectionFlags_.set(efOnlyAtoms); return me(); }
+ { selectionFlags_.set(efSelection_OnlyAtoms); return me(); }
/*! \brief
* Only accept static selections for this option.
*/
MyClass &onlyStatic()
- { selectionFlags_.set(efOnlyStatic); return me(); }
+ { selectionFlags_.set(efSelection_OnlyStatic); return me(); }
/*! \brief
* Handle dynamic selections for this option with position masks.
*
* \see SelectionPosition::selected()
*/
MyClass &dynamicMask()
- { selectionFlags_.set(efDynamicMask); return me(); }
+ { selectionFlags_.set(efSelection_DynamicMask); return me(); }
/*! \brief
* Disallow using atom coordinates as the reference positions.
*
* TODO: This option is not yet implemented.
*/
MyClass &dynamicOnlyWhole()
- { selectionFlags_.set(efDynamicOnlyWhole); return me(); }
+ { selectionFlags_.set(efSelection_DynamicOnlyWhole); return me(); }
/*! \brief
* Get an info object that can be used to alter the option after