/**
* @file generic_spec.h
* Container holding an item or a special "match all" item
*
* @remark Copyright 2003 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon
* @author Philippe Elie
*/
#ifndef GENERIC_SPEC_H
#define GENERIC_SPEC_H
#include <stdexcept>
#include <string>
#include <sstream>
#include "string_manip.h"
/**
* used to hold something like { int cpu_nr, bool is_all };
* to store a sub part of a samples filename see PP:3.21.
*/
template <class T>
class generic_spec
{
public:
/**
* build a default spec which match anything
*/
generic_spec();
/// build a spec from a string, valid argument are "all"
/// or a string convertible to T through istringtream(str) >> data
/// conversion is strict, no space are allowed at begin or end of str
void set(std::string const &);
/// return true if a specific value is held by this container
bool is_set() const {
return !is_all;
}
/// return the specific value (only if is_set() == true)
T const value() const {
if (!is_all)
return data;
throw std::out_of_range("generic_spec holds no value");
}
/// return true if rhs match this spec. Sub part of PP:3.24
bool match(T const & rhs) const {
return rhs == data;
}
/// return true if rhs match this spec. Sub part of PP:3.24
bool match(generic_spec<T> const & rhs) const {
return is_all || rhs.is_all || rhs.data == data;
}
private:
T data;
bool is_all;
};
template <class T>
generic_spec<T>::generic_spec()
:
data(T()),
is_all(true)
{
}
template <class T>
void generic_spec<T>::set(std::string const & str)
{
if (str == "all") {
is_all = true;
return;
}
is_all = false;
data = op_lexical_cast<T>(str);
}
/// We don't use generic_spec<string>, since it's probably an error to try
/// to use generic_spec<string> we specialize but don't define it to get a
/// link error (using generic_spec<string> is problematic because g.set("all")
/// is ambiguous)
template <>
void generic_spec<std::string>::set(std::string const & str);
#endif /* !GENERIC_SPEC_H */