Skip to content

Commit

Permalink
ResourceMap: Add string enum API
Browse files Browse the repository at this point in the history
  • Loading branch information
jschueller committed Feb 11, 2025
1 parent 7305c1a commit 5d0e02b
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 3 deletions.
53 changes: 52 additions & 1 deletion lib/src/Base/Common/ResourceMap.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "openturns/Path.hxx"
#include "openturns/Collection.hxx"
#include "openturns/XMLToolbox.hxx"

#ifdef OPENTURNS_HAVE_LIBXML2
#include <libxml/tree.h>
#endif
Expand Down Expand Up @@ -107,6 +108,11 @@ std::vector<String> ResourceMap::GetBoolKeys()
return GetInstance().lock().getBoolKeys();
}

std::vector<String> ResourceMap::GetStringEnum(const String & key)
{
return GetInstance().lock().getStringEnum(key);
}

/* Get a value in the map */
String ResourceMap::GetType(const String & key)
{
Expand Down Expand Up @@ -195,6 +201,11 @@ void ResourceMap::AddAsString(const String & key, const String & value)
GetInstance().lock().addAsString(key, value);
}

void ResourceMap::AddAsStringEnum(const String & key, const String & value, const std::vector<String> & enumValues)
{
GetInstance().lock().addAsStringEnum(key, value, enumValues);
}

void ResourceMap::AddAsBool(const String & key, const Bool value)
{
GetInstance().lock().addAsBool(key, value);
Expand All @@ -215,6 +226,11 @@ Bool ResourceMap::HasKey(const String & key)
return GetInstance().lock().hasKey(key);
}

Bool ResourceMap::HasStringEnum(const String & key)
{
return GetInstance().lock().hasStringEnum(key);
}

void ResourceMap::Reload()
{
return GetInstance().lock().reload();
Expand Down Expand Up @@ -319,14 +335,23 @@ Bool ResourceMap::hasKey(const String & key) const
|| (mapBool_.find(key) != mapBool_.end()));
}

Bool ResourceMap::hasStringEnum(const String & key) const
{
return mapStringEnum_.find(key) != mapStringEnum_.end();
}

void ResourceMap::removeKey(const String & key)
{
if (!hasKey(key))
throw InternalException(HERE) << "Key '" << key << "' is missing in ResourceMap";

const String keyType(getType(key));
if (keyType == "str")
{
mapString_.erase(mapString_.find(key));
if (mapStringEnum_.find(key) != mapStringEnum_.end())
mapStringEnum_.erase(mapStringEnum_.find(key));
}
else if (keyType == "float")
mapScalar_.erase(mapScalar_.find(key));
else if (keyType == "int")
Expand Down Expand Up @@ -453,6 +478,14 @@ void ResourceMap::setAsString(const String & key, const String & value)
const MapStringType::iterator it = mapString_.find(key);
if (it == mapString_.end())
throw InternalException(HERE) << "Key '" << key << "' is missing in ResourceMap as a String.";
const MapStringEnumType::iterator it2 = mapStringEnum_.find(key);
if (it2 != mapStringEnum_.end() && std::find(it2->second.begin(), it2->second.end(), value) == it2->second.end())
{
String possibleValues;
for (std::vector<String>::iterator it3 = it2->second.begin(); it3 != it2->second.end(); ++ it3)
possibleValues += *it3 + ", ";
throw InvalidArgumentException(HERE) << "Value for key '" << key << "' must be one of: " << possibleValues << " got '" << value << "'";
}
it->second = value;
}

Expand Down Expand Up @@ -487,6 +520,16 @@ void ResourceMap::addAsString(const String & key, const String & value)
mapString_[key] = value;
}

void ResourceMap::addAsStringEnum(const String & key, const String & value, const std::vector<String> & enumValues)
{
if (mapString_.find(key) != mapString_.end())
throw InternalException(HERE) << "Key '" << key << "' is already in ResourceMap as a String.";
mapString_[key] = value;
if (std::find(enumValues.begin(), enumValues.end(), value) == enumValues.end())
throw InternalException(HERE) << "Enum values do not contain value '" << value << "'";
mapStringEnum_[key] = enumValues;
}

void ResourceMap::addAsBool(const String & key, const Bool value)
{
if (mapBool_.find(key) != mapBool_.end())
Expand Down Expand Up @@ -718,7 +761,7 @@ void ResourceMap::loadDefaultConfiguration()
addAsUnsignedInteger("Contour-DefaultLevelsNumber", 10);
addAsBool("Contour-DefaultIsFilled", false);
addAsBool("Contour-DefaultDrawLabels", true);
addAsString("Contour-DefaultColorMapNorm", "linear");
addAsStringEnum("Contour-DefaultColorMapNorm", "linear", {"asinh", "linear", "log", "logit", "symlog", "rank"});
addAsString("Contour-DefaultColorMap", "viridis");
addAsString("Contour-DefaultColorBarPosition", "right");
addAsString("Contour-DefaultExtend", "both");
Expand Down Expand Up @@ -1817,6 +1860,14 @@ std::vector<String> ResourceMap::getStringKeys() const
return keys;
}

/* return the enum list associated to a key */
std::vector<String> ResourceMap::getStringEnum(const String & key)
{
const MapStringEnumType::const_iterator it = mapStringEnum_.find(key);
if (it != mapStringEnum_.end()) return it->second;
throw InternalException(HERE) << "Key '" << key << "' has no string enum.";
}

std::vector<String> ResourceMap::getBoolKeys() const
{
std::vector<String> keys;
Expand Down
14 changes: 14 additions & 0 deletions lib/src/Base/Common/openturns/ResourceMap.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public:

/** Add a value in the maps */
static void AddAsString(const String & key, const String & value);
static void AddAsStringEnum(const String & key, const String & value, const std::vector<String> & enumValues);
static void AddAsBool(const String & key, const Bool value);
static void AddAsUnsignedInteger(const String & key, const UnsignedInteger value);
static void AddAsScalar(const String & key, const Scalar value);
Expand All @@ -82,10 +83,14 @@ public:
static std::vector<String> GetScalarKeys();
static std::vector<String> GetUnsignedIntegerKeys();
static std::vector<String> GetBoolKeys();
static std::vector<String> GetStringEnum(const String & key);

/** Is the specific key present ? */
static Bool HasKey(const String & key);

/** Is the specific key associated to a string enum ? */
static Bool HasStringEnum(const String & key);

/** Remove a key */
static void RemoveKey(const String & key);

Expand Down Expand Up @@ -124,6 +129,9 @@ protected:
*/
std::vector<String> getBoolKeys() const;

/** return the enum list associated to a key */
std::vector<String> getStringEnum(const String & key);

/** Method for retrieving information from the resource map
* @param key The name under which the value is stored in the ResourceMap
* @return the type of the key
Expand Down Expand Up @@ -220,6 +228,7 @@ protected:
* @param value The value written to a string
*/
void addAsString(const String & key, const String & value);
void addAsStringEnum(const String & key, const String & value, const std::vector<String> & enumValues);

/** Method for adding information into the resource map
* @param key The name under which the value is stored in the ResourceMap
Expand All @@ -242,6 +251,9 @@ protected:
/** Is the specific key present ? */
Bool hasKey(const String & key) const;

/** Is the specific key associated to a string enum ? */
Bool hasStringEnum(const String & key) const;

/** Remove a key from the resource map */
void removeKey(const String & key);

Expand Down Expand Up @@ -280,11 +292,13 @@ private:
typedef std::map< String, Scalar > MapScalarType;
typedef std::map< String, UnsignedInteger > MapUnsignedIntegerType;
typedef std::map< String, Bool > MapBoolType;
typedef std::map< String, std::vector< String > > MapStringEnumType;

MapStringType mapString_;
MapScalarType mapScalar_;
MapUnsignedIntegerType mapUnsignedInteger_;
MapBoolType mapBool_;
MapStringEnumType mapStringEnum_;

friend struct ResourceMap_init;
}; /* class ResourceMap */
Expand Down
54 changes: 54 additions & 0 deletions python/src/ResourceMap_doc.i.in
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,30 @@ Examples

// ---------------------------------------------------------------------

%feature("docstring") OT::ResourceMap::AddAsStringEnum
"Add a new string enum parameter.

Similar to :meth:`AddAsString` except :meth:`SetAsString` calls will make sure the
value associated to that key is part of the list of possible supplied values.

Parameters
----------
key : str
An identifier associated to the parameter.
value : str
The value associated to that key. The key is added to the string map even if
it already exists in another map (float, int or bool).
enumValues : sequence of str
Possible values

Examples
--------
>>> import openturns as ot
>>> ot.ResourceMap.AddAsStringEnum('View-ImageFormat3', 'png', ['png', 'jpg', 'bmp'])
>>> ot.ResourceMap.RemoveKey('View-ImageFormat3')"

// ---------------------------------------------------------------------

%feature("docstring") OT::ResourceMap::GetAsString
"Access a string parameter.

Expand Down Expand Up @@ -413,6 +437,21 @@ keys : tuple of str

// ---------------------------------------------------------------------

%feature("docstring") OT::ResourceMap::GetStringEnum
"Get the possible values of a string enum.

Parameters
----------
key : str
An identifier associated to the parameter.

Returns
-------
enums : tuple of str
The list of possible values."

// ---------------------------------------------------------------------

%feature("docstring") OT::ResourceMap::HasKey
"Check if an entry exists.

Expand All @@ -428,6 +467,21 @@ has_key : bool

// ---------------------------------------------------------------------

%feature("docstring") OT::ResourceMap::HasStringEnum
"Check if an entry is associated to a string enum.

Parameters
----------
key : str
An identifier associated to the parameter.

Returns
-------
hasStringEnum : bool
Whether an entry with that key exists."

// ---------------------------------------------------------------------

%feature("docstring") OT::ResourceMap::Reload
"Reload the configuration.

Expand Down
5 changes: 3 additions & 2 deletions python/test/t_ResourceMap_missing.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
resourcemap_lines += f.read().splitlines()
resourcemap_content = {}
for line in resourcemap_lines:
match = re.search(r'addAs(\w+)\("([\w\-]+)",[ ]*([\w\d\.\-\"]+)\);', line)
match = re.search(r'addAs(\w+)\("([\w\-]+)",[ ]*([\w\d\.\-\"]+)[\),]', line)
if match is not None:
key, vtype, value = match.group(2), match.group(1), match.group(3)
print(key, vtype, value)
if key == "SymbolicParser-Backend":
continue
if vtype == "Scalar":
Expand All @@ -24,7 +25,7 @@
resourcemap_content[key] = int(value)
elif vtype == "Bool":
resourcemap_content[key] = {"true": True, "false": False}[value]
elif vtype == "String":
elif vtype.startswith("String"):
resourcemap_content[key] = value.strip('"')
else:
raise ValueError(f"got {key}")
Expand Down
12 changes: 12 additions & 0 deletions python/test/t_ResourceMap_std.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,15 @@
"Extract from ResourceMap: Cache-MaxSize -> ",
ot.ResourceMap.Get("Cache-MaxSize"),
)

# check string enum api
ot.ResourceMap.AddAsStringEnum("foo", "a", ["a", "b"])
assert ot.ResourceMap.HasStringEnum("foo")
assert ot.ResourceMap.GetStringEnum("foo") == ("a", "b")
ot.ResourceMap.SetAsString("foo", "b")
ok = False
try:
ot.ResourceMap.SetAsString("foo", "z")
except Exception:
ok = True
assert ok

0 comments on commit 5d0e02b

Please sign in to comment.