From d03c51f00809b458d913f1c47a7f383f5da1dcc7 Mon Sep 17 00:00:00 2001
From: Daniele Rapetti <5535617+Iximiel@users.noreply.github.com>
Date: Wed, 18 Dec 2024 15:27:33 +0100
Subject: [PATCH 01/19] Setting typo-safe types for keyword type and datatype
for keywords
self documenting addInputKeyword and mking the types public
applied the example to dumpforces
making the enum bitmask makes everithing compile :D
reworking "add"
reserve and use
---
src/generic/DumpForces.cpp | 2 +-
src/tools/BitmaskEnum.h | 127 +++++++++++
src/tools/Keywords.cpp | 452 ++++++++++++++++++++++++++-----------
src/tools/Keywords.h | 116 +++++++---
4 files changed, 526 insertions(+), 171 deletions(-)
create mode 100644 src/tools/BitmaskEnum.h
diff --git a/src/generic/DumpForces.cpp b/src/generic/DumpForces.cpp
index 704853fbb1..03bfebd4b0 100644
--- a/src/generic/DumpForces.cpp
+++ b/src/generic/DumpForces.cpp
@@ -71,7 +71,7 @@ void DumpForces::registerKeywords(Keywords& keys) {
Action::registerKeywords(keys);
ActionPilot::registerKeywords(keys);
ActionWithArguments::registerKeywords(keys);
- keys.addInputKeyword("compulsory","ARG","scalar","the labels of the values whose forces should be output");
+ keys.addInputKeyword("compulsory","ARG",Keywords::argType::scalar,"the labels of the values whose forces should be output");
keys.add("compulsory","STRIDE","1","the frequency with which the forces should be output");
keys.add("compulsory","FILE","the name of the file on which to output the forces");
keys.add("compulsory","FMT","%15.10f","the format with which the derivatives should be output");
diff --git a/src/tools/BitmaskEnum.h b/src/tools/BitmaskEnum.h
new file mode 100644
index 0000000000..6e6567c15c
--- /dev/null
+++ b/src/tools/BitmaskEnum.h
@@ -0,0 +1,127 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Copyright (c) 2024 The plumed team
+ (see the PEOPLE file at the root of the distribution for a list of names)
+
+ See http://www.plumed.org for more information.
+
+ This file is part of plumed, version 2.
+
+ plumed is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ plumed is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with plumed. If not, see .
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+
+#ifndef __PLUMED_tools_BitmaskEnum_h
+#define __PLUMED_tools_BitmaskEnum_h
+#include
+
+namespace PLMD {
+
+/// support struct for setting up some operations on enum types
+template< typename enum_type >
+struct BitmaskEnum {
+ //example traits
+ //Use: specialize with extra traits (see Keywords.h)
+ // Example:
+ /*
+ // Please note that the 0 value is not implemented (it is reserved as a result of mask not matching masks)
+ enum class argType {scalar=1,grid=1<<2,vector=1<<3,matrix=1<<4};
+ template<>
+ struct BitmaskEnum< argType > {
+ static constexpr bool has_valid = true;
+ static constexpr bool has_bit_or = true;
+ static constexpr bool has_bit_and = true;
+ };
+ */
+ // Currenlty we have implemented:
+ // static constexpr bool has_valid = true;
+ // static constexpr bool has_bit_or = true;
+ // static constexpr bool has_bit_and = true;
+};
+
+/**
+ @brief Perform a bitwise OR between two enum values.
+
+This operator is only defined if in the declaration you define specialize BitmaskEnum
+for the enum type in question with the `has_bit_or` trait.
+
+ \param a The first enum value.
+ \param b The second enum value.
+ \return The result of performing a bitwise OR between the two values.
+*/
+template< typename enumtype > // SFINAE makes function contingent on trait
+typename std::enable_if_t< BitmaskEnum< enumtype >::has_bit_or,enumtype>
+operator|( enumtype a, enumtype b ) {
+ return static_cast(static_cast>(a) |
+ static_cast>(b));
+}
+
+/**
+ @brief Perform a bitwise AND between two enum values.
+
+This operator is only defined if in the declaration you define specialize BitmaskEnum
+for the enum type in question with the `has_bit_and` trait.
+
+ \param a The first enum value.
+ \param b The second enum value.
+ \return The result of performing a bitwise AND between the two values.
+*/
+template< typename enumtype > // SFINAE makes function contingent on trait
+typename std::enable_if_t< BitmaskEnum< enumtype >::has_bit_and,enumtype>
+operator&( enumtype a, enumtype b ) {
+ return static_cast(static_cast>(a) &
+ static_cast>(b));
+}
+
+
+/**
+ @brief Test if an enum value is valid.
+
+This function is only defined if in the declaration you define specialize BitmaskEnum
+for the enum type in question with the `has_valid` trait.
+
+
+ @param a The enum value to test.
+ @return true if the enum value is not equal to zero, false otherwise.
+
+ @code
+ enum class myenum { A=1,B=1<<1,C=1<<2 };
+ //then activate the functions `|` and `valid`
+ template<>
+ struct BitmaskEnum< Keywords::argType > {
+ static constexpr bool has_valid = true;
+ static constexpr bool has_bit_or = true;
+ };
+ //...code...
+ myenum val = myenum::A | myenum::C;
+ if(PLMD::valid( val | myenum::A))
+ std::cout << "Is A\n";
+ if(PLMD::valid(val | myenum::B))
+ std::cout << "Is B\n";
+ if(PLMD::valid(val | myenum::C))
+ std::cout << "Is C\n";
+ //will produce:
+ //Is A
+ //Is C
+ @endcode
+
+ @return true if the enum value is not equal to zero, false otherwise.
+*/
+template< typename enumtype > // SFINAE makes function contingent on trait
+typename std::enable_if_t< BitmaskEnum< enumtype >::has_valid,bool>
+valid( enumtype a) {
+ return static_cast>(a)!=0;
+}
+
+} // namespace PLMD
+
+#endif //__PLUMED_tools_BitmaskEnum_h
\ No newline at end of file
diff --git a/src/tools/Keywords.cpp b/src/tools/Keywords.cpp
index d14eb195a8..65c9a96587 100644
--- a/src/tools/Keywords.cpp
+++ b/src/tools/Keywords.cpp
@@ -24,45 +24,185 @@
#include "Tools.h"
#include
#include
-
+#include
namespace PLMD {
-Keywords::KeyType::KeyType( const std::string& type ) {
- if( type=="compulsory" ) {
- style=compulsory;
- } else if( type=="flag" ) {
- style=flag;
- } else if( type=="optional" ) {
- style=optional;
- } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
- style=atoms;
- } else if( type=="hidden" ) {
- style=hidden;
- } else if( type=="vessel" ) {
- style=vessel;
- } else {
- plumed_massert(false,"invalid keyword specifier " + type);
+std::string toString(Keywords::argType at) {
+ //the simple cases
+ switch (at) {
+ case Keywords::argType::scalar:
+ return "scalar";
+
+ case Keywords::argType::grid:
+ return "grid";
+
+ case Keywords::argType::vector:
+ return "vector";
+
+ case Keywords::argType::matrix:
+ return "matrix";
+ }
+ //the not simple cases
+ {
+ std::string ret="";
+ std::string next="";
+ if(valid(at & Keywords::argType::scalar)) {
+ ret+="scalar";
+ next="/";
+ }
+ if(valid(at & Keywords::argType::grid)) {
+ ret+=next+"grid";
+ next="/";
+ }
+ if(valid(at & Keywords::argType::vector)) {
+ ret+=next+"vector";
+ next="/";
+ }
+ if(valid(at & Keywords::argType::matrix)) {
+ ret+=next+"matrix";
+ }
+ return ret;
+ }
+ //the return is outsids so the compile should block the compilation
+ //when expanding the enum without updating the toString
+ return "";
+}
+
+Keywords::argType stoat(std::string_view str) {
+ using namespace std::literals;
+ if(auto pos = str.find("/"sv); pos!=str.npos) {
+ //here we can express that we do not want certain combinations
+ auto val=stoat(str.substr(0,pos));
+ return val | stoat(str.substr(pos+1));
+ }
+ if (str == "scalar") {
+ return Keywords::argType::scalar;
+ }
+ if (str == "grid") {
+ return Keywords::argType::grid;
+ }
+ if (str == "vector") {
+ return Keywords::argType::vector;
+ }
+ if (str == "matrix") {
+ return Keywords::argType::matrix;
+ }
+ // Handle the case where the string does not match any enum value.
+ plumed_massert(false,"invalid argType specifier " + std::string(str));
+}
+
+std::string toString(Keywords::componentType at) {
+ switch (at) {
+ case Keywords::componentType::scalar:
+ return "scalar";
+
+ case Keywords::componentType::grid:
+ return "grid";
+
+ case Keywords::componentType::vector:
+ return "vector";
+
+ case Keywords::componentType::matrix:
+ return "matrix";
+
+ case Keywords::componentType::atom:
+ return "atom";
+
+ case Keywords::componentType::atoms:
+ return "atoms";
+ }
+ //the not simple cases
+ {
+ std::string ret="";
+ std::string next="";
+ if(valid(at & Keywords::componentType::scalar)) {
+ ret+="scalar";
+ next="/";
+ }
+ if(valid(at & Keywords::componentType::grid)) {
+ ret+=next+"grid";
+ next="/";
+ }
+ if(valid(at & Keywords::componentType::vector)) {
+ ret+=next+"vector";
+ next="/";
+ }
+ if(valid(at & Keywords::componentType::matrix)) {
+ ret+=next+"matrix";
+ next="/";
+ }
+ //I do not think these two are necessary
+ if(valid(at & Keywords::componentType::atom)) {
+ ret+=next+"atom";
+ }
+ if(valid(at & Keywords::componentType::atoms)) {
+ ret+=next+"atoms";
+ }
+ return ret;
+ }
+ //the return is outsids so the compile should block the compilation
+ //when expanding the enum without updating the toString
+ return "";
+}
+
+inline Keywords::componentType stoct(std::string_view str) {
+ using namespace std::literals;
+ if(auto pos = str.find("/"sv); pos!=str.npos) {
+ //here we can express that we do not want certain combinations
+ auto val=stoct(str.substr(0,pos));
+ return val | stoct(str.substr(pos+1));
+ }
+ if (str == "scalar") {
+ return Keywords::componentType::scalar;
+ }
+ if (str == "grid") {
+ return Keywords::componentType::grid;
+ }
+ if (str == "vector") {
+ return Keywords::componentType::vector;
+ }
+ if (str == "matrix") {
+ return Keywords::componentType::matrix;
}
+ if (str == "atom") {
+ return Keywords::componentType::atom;
+ }
+ if (str == "atoms") {
+ return Keywords::componentType::atoms;
+ }
+
+ plumed_massert(false,"invalid componentType specifier " + std::string(str));
}
-void Keywords::KeyType::setStyle( const std::string& type ) {
+Keywords::KeyType::keyStyle Keywords::KeyType::keyStyleFromString(std::string_view type ) {
if( type=="compulsory" ) {
- style=compulsory;
+ return keyStyle::compulsory;
} else if( type=="flag" ) {
- style=flag;
+ return keyStyle::flag;
} else if( type=="optional" ) {
- style=optional;
- } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
- style=atoms;
+ return keyStyle::optional;
+ //this is special: some atoms keywords have extra characters usually a "-" followed by a number
+ } else if( type.find("atoms")!=type.npos || type.find("residues")!=type.npos) {
+ return keyStyle::atoms;
} else if( type=="hidden" ) {
- style=hidden;
+ return keyStyle::hidden;
} else if( type=="vessel" ) {
- style=vessel;
+ return keyStyle::vessel;
} else {
- plumed_massert(false,"invalid keyword specifier " + type);
+ plumed_massert(false,"invalid keyword specifier " + std::string(type));
}
}
+Keywords::KeyType::KeyType( std::string_view type )
+ : style(keyStyleFromString(type)) {}
+
+Keywords::KeyType::KeyType( Keywords::KeyType::keyStyle type )
+ : style(type) {}
+
+void Keywords::KeyType::setStyle( std::string_view type ) {
+ style=keyStyleFromString(type);
+}
+
std::string Keywords::getStyle( const std::string & k ) const {
plumed_massert( types.count(k), "Did not find keyword " + k );
return (types.find(k)->second).toString();
@@ -72,7 +212,9 @@ void Keywords::add( const Keywords& newkeys ) {
newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs );
}
-void Keywords::copyData( std::vector& kk, std::vector& rk, std::map& tt, std::map& am,
+void Keywords::copyData( std::vector& kk,
+ std::vector& rk,
+ std::map>& tt, std::map& am,
std::map& docs, std::map& bools, std::map& nums,
std::map& atags, std::vector& cnam, std::map& ck,
std::map& cd ) const {
@@ -139,50 +281,57 @@ void Keywords::copyData( std::vector& kk, std::vector&
}
}
-void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
- plumed_assert( !exists(k) && !reserved(k) );
- std::string fd, lowkey=k;
- // Convert to lower case
- std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
- return std::tolower(c);
- });
-// Remove any underscore characters
- for(unsigned i=0;; ++i) {
- std::size_t num=lowkey.find_first_of("_");
- if( num==std::string::npos ) {
- break;
- }
- lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
- }
- if( t=="vessel" ) {
- fd = d + " The final value can be referenced using label." + lowkey;
- if(d.find("flag")==std::string::npos)
- fd += ". You can use multiple instances of this keyword i.e. " +
- k +"1, " + k + "2, " + k + "3... The corresponding values are then "
+#define NUMBERED_DOCSTRING(key) ". You can use multiple instances of this keyword i.e. " + std::string(key) +"1, " + std::string(key) + "2, " + std::string(key) + "3..."
+void Keywords::reserve( const std::string & keytype,
+ const std::string & key,
+ const std::string & docstring ) {
+ plumed_assert( !exists(key) && !reserved(key) );
+ std::string t_type{keytype};
+ bool isNumbered = keytype=="numbered";
+ if( isNumbered ) {
+ t_type="optional";
+ }
+ //let's fail asap in case of typo
+ auto type = KeyType(t_type);
+ plumed_assert( !exists(key) && !reserved(key) );
+
+ std::string fd{docstring};
+ bool allowMultiple= false;
+ if( type.isVessel() ) {
+ // Convert to lower case
+ std::string lowkey{key};
+ std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
+ return std::tolower(c);
+ });
+ // Remove any underscore characters
+ lowkey.erase(std::remove(lowkey.begin(), lowkey.end(), '_'), lowkey.end());
+
+ fd += " The final value can be referenced using label." + lowkey;
+ if(docstring.find("flag")==std::string::npos) {
+ fd += NUMBERED_DOCSTRING(key) " The corresponding values are then "
"referenced using label."+ lowkey +"-1, label." + lowkey +
"-2, label." + lowkey + "-3...";
- allowmultiple.insert( std::pair(k,true) );
- types.insert( std::pair(k,KeyType("vessel")) );
- } else if( t=="numbered" ) {
- fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
- allowmultiple.insert( std::pair(k,true) );
- types.insert( std::pair(k,KeyType("optional")) );
+ }
+ allowMultiple = true;
+ } else if( isNumbered ) {
+ fd += NUMBERED_DOCSTRING(key);
+ allowMultiple = true;
} else {
- fd = d;
- if( t=="atoms" && isaction ) {
- fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
+ //if( type.isAtomList() && isaction ) {//<- why not this? atoms could also be "residues" or "atoms-n"
+ if( keytype=="atoms" && isaction ) {
+ fd += ". For more information on how to specify lists of atoms see \\ref Group";
}
- allowmultiple.insert( std::pair(k,false) );
- types.insert( std::pair(k,KeyType(t)) );
- if( (types.find(k)->second).isAtomList() ) {
- atomtags.insert( std::pair(k,t) );
+ if( type.isAtomList() ) {
+ atomtags.insert( std::pair(key,keytype) );
}
}
- documentation.insert( std::pair(k,fd) );
- reserved_keys.push_back(k);
+ types.insert( std::pair(key,type) );
+ allowmultiple.insert( std::pair(key,allowMultiple) );
+ documentation.insert( std::pair(key,fd) );
+ reserved_keys.emplace_back(key);
}
-void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
+void Keywords::reserveFlag(const std::string & k, const bool def, const std::string & d ) {
plumed_assert( !exists(k) && !reserved(k) );
std::string defstr;
if( def ) {
@@ -190,7 +339,7 @@ void Keywords::reserveFlag( const std::string & k, const bool def, const std::st
} else {
defstr="( default=off ) ";
}
- types.insert( std::pair(k,KeyType("flag")) );
+ types.insert( std::pair(k,KeyType::keyStyle::flag) );
std::string fd,lowkey=k;
std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
return std::tolower(c);
@@ -202,13 +351,14 @@ void Keywords::reserveFlag( const std::string & k, const bool def, const std::st
reserved_keys.push_back(k);
}
-void Keywords::use( const std::string & k ) {
- plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
- for(unsigned i=0; i(k,true) );
- types.insert( std::pair(k, KeyType("optional")) );
+ fd=docstring;
+ if( isNumbered ) {
+ fd += NUMBERED_DOCSTRING(key);
} else {
- fd=d;
- allowmultiple.insert( std::pair(k,false) );
- types.insert( std::pair(k,KeyType(t)) );
- if( (types.find(k)->second).isAtomList() ) {
- atomtags.insert( std::pair(k,t) );
+ if( (types.find(key)->second).isAtomList() ) {
+ //keytype may be "residues" or something like "atoms-3"
+ atomtags.insert( std::pair(key,keytype) );
}
}
- if( t=="atoms" && isaction ) {
- fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
+ allowmultiple.insert( std::pair(key,isNumbered) );
+ types.insert( std::pair(key, type) );
+ if( type.isAtomList() && isaction ) {
+ fd += ". For more information on how to specify lists of atoms see \\ref Group";
}
- documentation.insert( std::pair(k,fd) );
- keys.push_back(k);
+ documentation.insert( std::pair(key,fd) );
+ keys.emplace_back(key);
}
-void Keywords::addInputKeyword( const std::string & t, const std::string & k, const std::string & ttt, const std::string & d ) {
- if( exists(k) ) {
- remove(k);
- argument_types[k] = ttt;
- } else {
- argument_types.insert( std::pair(k,ttt) );
- }
- add( t, k, d );
+void Keywords::addInputKeyword( const std::string & typekey,
+ const std::string & key,
+ const std::string & datatype,
+ const std::string & docstring ) {
+ addInputKeyword(typekey,key,stoat(datatype),docstring);
}
-void Keywords::addInputKeyword( const std::string & t, const std::string & k, const std::string & ttt, const std::string& def, const std::string & d ) {
- if( exists(k) ) {
- remove(k);
- argument_types[k] = ttt;
- } else {
- argument_types.insert( std::pair(k,ttt) );
+void Keywords::addInputKeyword( const std::string & typekey,
+ const std::string & key,
+ argType datatype,
+ const std::string & docstring ) {
+ if( exists(key) ) {
+ remove(key);
+ }
+ //insert({k,datatype}) Inserts element(s) into the container, if the container doesn't already contain an element with an equivalent key.[cit.]
+ //operator[] inserts if the key doesn't exist, or overwrites if it does
+ argument_types[key] = datatype;
+ add( typekey, key, docstring );
+}
+
+void Keywords::addInputKeyword( const std::string & keyType,
+ const std::string & key,
+ const std::string & datatype,
+ const std::string & defaultV,
+ const std::string & docstring ) {
+ addInputKeyword(keyType,key,stoat(datatype),defaultV,docstring);
+}
+
+void Keywords::addInputKeyword( const std::string & keyType,
+ const std::string & key,
+ argType datatype,
+ const std::string & defaultV,
+ const std::string & docstring ) {
+ if( exists(key) ) {
+ remove(key);
}
- add( t, k, def, d );
+ argument_types[key] = datatype;
+ add( keyType, key, defaultV, docstring );
}
-void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ) {
- plumed_massert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" ), "failing on keyword " + k ); // An optional keyword can't have a default
- types.insert( std::pair(k, KeyType(t)) );
- documentation.insert( std::pair(k,"( default=" + def + " ) " + d) );
- allowmultiple.insert( std::pair(k,false) );
- numdefs.insert( std::pair(k,def) );
- keys.push_back(k);
+void Keywords::add( std::string_view keytype,
+ std::string_view key,
+ std::string_view defaultValue,
+ std::string_view docstring ) {
+ //let's fail asap in case of typo
+ auto type = KeyType(keytype);
+ // An optional keyword can't have a default
+ plumed_massert( !exists(key) && !reserved(key) &&
+ (type.isCompulsory() || type.isHidden() ), "failing on keyword " + std::string(key) );
+ types.insert( std::pair {key, type} );
+ documentation.insert( std::pair(key,"( default=" + std::string(defaultValue) + " ) " + std::string(docstring) ));
+ allowmultiple.insert( std::pair(key,false) );
+ numdefs.insert( std::pair(key,defaultValue) );
+ keys.emplace_back(key);
}
void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
@@ -294,14 +480,16 @@ void Keywords::remove( const std::string & k ) {
unsigned j=0, n=0;
while(true) {
- for(j=0; j(name,key) );
cdocs.insert( std::pair(name,descr) );
- ctypes.insert( std::pair(name,type) );
+ ctypes.insert( std::pair(name,stoct(type)) );
cnames.push_back(name);
}
@@ -836,11 +1014,11 @@ void Keywords::setValueDescription( const std::string& type, const std::string&
if( !outputComponentExists(".#!value") ) {
ckey.insert( std::pair(".#!value","default") );
cdocs.insert( std::pair(".#!value",descr) );
- ctypes.insert( std::pair(".#!value",type) );
+ ctypes.insert( std::pair(".#!value",stoct (type)) );
cnames.push_back(".#!value");
} else {
cdocs[".#!value"] = descr;
- ctypes[".#!value"] = type;
+ ctypes[".#!value"] = stoct(type);
}
}
@@ -885,34 +1063,34 @@ bool Keywords::componentHasCorrectType( const std::string& name, const std::size
sname=name;
}
- if( thisactname=="CENTER" && ctypes.find(sname)->second=="atom" ) {
+ if( thisactname=="CENTER" && (components.at(sname).type== componentType::atom || components.at(sname).type== componentType::atoms) ) {
return true;
}
if( rank==0 ) {
- return (ctypes.find(sname)->second.find("scalar")!=std::string::npos);
+ return (valid(ctypes.find(sname)->second | componentType::scalar));
} else if( hasderiv ) {
- return (ctypes.find(sname)->second.find("grid")!=std::string::npos);
+ return (valid(ctypes.find(sname)->second | componentType::grid));
} else if( rank==1 ) {
- return (ctypes.find(sname)->second.find("vector")!=std::string::npos);
+ return (valid(ctypes.find(sname)->second | componentType::vector));
} else if( rank==2 ) {
- return (ctypes.find(sname)->second.find("matrix")!=std::string::npos);
+ return (valid(ctypes.find(sname)->second | componentType::matrix ));
}
return false;
}
bool Keywords::checkArgumentType( const std::size_t& rank, const bool& hasderiv ) const {
for(auto const& x : argument_types ) {
- if( rank==0 && x.second.find("scalar")!=std::string::npos ) {
+ if( rank==0 && valid(x.second | argType::scalar)) {
return true;
}
- if( hasderiv && x.second.find("grid")!=std::string::npos ) {
+ if( hasderiv && valid(x.second | argType::grid)) {
return true;
}
- if( rank==1 && x.second.find("vector")!=std::string::npos ) {
+ if( rank==1 && valid(x.second | argType::vector)) {
return true;
}
- if( rank==2 && x.second.find("matrix")!=std::string::npos ) {
+ if( rank==2 && valid(x.second | argType::matrix)) {
return true;
}
}
@@ -924,7 +1102,7 @@ std::string Keywords::getArgumentType( const std::string& name ) const {
if( argument_types.find(name)==argument_types.end() ) {
return "";
}
- return argument_types.find(name)->second;
+ return toString(argument_types.find(name)->second);
}
std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
@@ -932,7 +1110,7 @@ std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
}
std::string Keywords::getOutputComponentType( const std::string& name ) const {
- return ctypes.find(name)->second;
+ return toString( components.find(name)->second.type);
}
std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
diff --git a/src/tools/Keywords.h b/src/tools/Keywords.h
index 6d40ff1863..6c93eb58aa 100644
--- a/src/tools/Keywords.h
+++ b/src/tools/Keywords.h
@@ -23,10 +23,11 @@
#define __PLUMED_tools_Keywords_h
#include
#include
-#include
+#include
#include