Searching through a const std::map - c++

I am working on one of my classes and I have come upon a stumbling block. I'll give you a sample of my source only the names of classes, methods and variable names are different, but the implementation is the same. You will see my problem/s, question/s & concern/s within the code block to the appropriate function.
MyClass.h
#ifndef MY_CLASS_H
#define MY_CLASS_H
const std::string strOne = std::string( "one" );
const std::string strTwo = std::string( "two" );
const std::string strThree = std::string( "three" );
const std::string strUnknown = std::string( "unknown" );
enum Count {
ONE,
TWO,
THREE,
UNKNOWN
};
class MyClass {
private:
const std::map<Count, const std::string> m_mCount = createCountMap();
unsigned short m_uCount;
std::vector<std::string> m_vItems;
std::multimap<const std::string, const std::string> m_mmAssociatedItems;
public:
MyClass();
MyClass( const std::string strItem1, const std::string strItem2 );
static MyClass* get();
void addItem( Count type, const std::string& strItem2 );
void addItem( const std::string& strItem1, const std::string& strItem2 );
private:
static const std::map<Count, const std::string> createCountMap();
};
#endif // MY_CLASS_H
MyClass.cpp
#include "stdafx.h"
#include "MyClass.h"
static MyClass* s_pMyClass = nullptr;
const std::map<Count, const std::string> MyClass:createCountMap() {
std::map<Count, const std::string> m;
m.insert( std::make_pair( Count::ONE, strOne ) );
m.insert( std::make_pair( Count::TWO, strTwo ) );
m.insert( std::make_pair( Count::Three, strThree ) );
m.insert( std::make_pair( Count::UNKNOWN, strUnknown ) );
return m;
} // createCountMap
MyClass* MyClass::get() {
if ( !s_pMyClass ) {
return nullptr;
}
return s_pMyClass;
} // get
MyClass::MyClass() : m_uCount( 0 ) {
m_vItems.clear();
m_mmAssociatedItems.clear();
} // MyClass
MyClass::MyClass( const std::string& strItem1, const std::string& strItem2 ) :
m_uCount( 0 ) {
addItem( strItem1, strItem2 );
} // MyClass
void MyClass::addItem( Count type, const std::string& strItem2 ) {
const std::map<Count, const std::string>::const_iterator it = m_mCount.find( type );
if ( it == m_mCount.end() ) {
// Did not find a valid item key!
// Throw Exception Here!
}
m_vItems.push_back( strItem2 );
m_mmAssociatedItems.insert( std::make_pair( it->second, m_vItems.at( m_uCount ) ) );
++m_uCount;
}
void MyClass::addItem( const std::string& strItem1, const std::string& strItem2 ) {
// I need to do a similar thing as above instead of looking through my
// const std::map at the key values for a match, with this overloaded
// function call I need to use strItem1 as the search item to see if it
// is within the contents of this map which would be the map's ->second
// value. If not throw a similar error as above otherwise once it is
// found populate my vector and multimap same as above and increment
// my count variable.
// This would logically be my next step
const std::map<Count, const std::string>::const_iterator it = m_mCount.begin();
// It Is Within This For Loop That It Fails To Compile! It
// Fails At The it++ Part! Is There A Way Around This? Or
// Am I Missing Something Simple?
for ( ; it != m_mCount.end(); it++ ) {
// If strItem1 == it->second && it != m_mCount.end()
// found it, add items, if not throw error
}
m_vItems.push_back( strItem2 );
m_mmAssociatedItems.insert( std::make_pair( strItem1, strItem2 ) );
++m_uCount;
}
In my source, it is this second function which is more important then the first! Any Help or suggestions is very much appreciated.

const std::map<Count, const std::string>::const_iterator it = m_mCount.begin();
The first const should be removed. Otherwise it cannot be moved forward, and you cannot iterate through m_mCount.

Related

Expand wildcard path (like shell) [duplicate]

I want to iterate over all files in a directory matching something like somefiles*.txt.
Does boost::filesystem have something built in to do that, or do I need a regex or something against each leaf()?
EDIT: As noted in the comments, the code below is valid for versions of boost::filesystem prior to v3. For v3, refer to the suggestions in the comments.
boost::filesystem does not have wildcard search, you have to filter files yourself.
This is a code sample extracting the content of a directory with a boost::filesystem's directory_iterator and filtering it with boost::regex:
const std::string target_path( "/my/directory/" );
const boost::regex my_filter( "somefiles.*\.txt" );
std::vector< std::string > all_matching_files;
boost::filesystem::directory_iterator end_itr; // Default ctor yields past-the-end
for( boost::filesystem::directory_iterator i( target_path ); i != end_itr; ++i )
{
// Skip if not a file
if( !boost::filesystem::is_regular_file( i->status() ) ) continue;
boost::smatch what;
// Skip if no match for V2:
if( !boost::regex_match( i->leaf(), what, my_filter ) ) continue;
// For V3:
//if( !boost::regex_match( i->path().filename().string(), what, my_filter ) ) continue;
// File matches, store it
all_matching_files.push_back( i->leaf() );
}
(If you are looking for a ready-to-use class with builtin directory filtering, have a look at Qt's QDir.)
There is a Boost Range Adaptors way:
#define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
#include <boost/filesystem.hpp>
#include <boost/range/adaptors.hpp>
namespace bfs = boost::filesystem;
namespace ba = boost::adaptors;
const std::string target_path( "/my/directory/" );
const boost::regex my_filter( "somefiles.*\.txt" );
boost::smatch what;
for (auto &entry: boost::make_iterator_range(bfs::directory_iterator(target_path), {})
| ba::filtered(static_cast<bool (*)(const bfs::path &)>(&bfs::is_regular_file))
| ba::filtered([&](const bfs::path &path){ return boost::regex_match(path.filename().string(), what, my_filter); })
)
{
// There are only files matching defined pattern "somefiles*.txt".
std::cout << entry.path().filename() << std::endl;
}
My solution is essentially the same as Julien-L, but encapsulated in the include file it is nicer to use. Implemented using boost::filesystem v3. I guess that something like that is not included in the boost::filesystem directly because it would introduce dependency on boost::regex.
#include "FilteredDirectoryIterator.h"
std::vector< std::string > all_matching_files;
std::for_each(
FilteredDirectoryIterator("/my/directory","somefiles.*\.txt"),
FilteredDirectoryIterator(),
[&all_matching_files](const FilteredDirectoryIterator::value_type &dirEntry){
all_matching_files.push_back(dirEntry.path());
}
);
alternatively use FilteredRecursiveDirectoryIterator for recursive sub directories search:
#include "FilteredDirectoryIterator.h"
std::vector< std::string > all_matching_files;
std::for_each(
FilteredRecursiveDirectoryIterator("/my/directory","somefiles.*\.txt"),
FilteredRecursiveDirectoryIterator(),
[&all_matching_files](const FilteredRecursiveDirectoryIterator::value_type &dirEntry){
all_matching_files.push_back(dirEntry.path());
}
);
FilteredDirectoryIterator.h
#ifndef TOOLS_BOOST_FILESYSTEM_FILTEREDDIRECTORYITERATOR_H_
#define TOOLS_BOOST_FILESYSTEM_FILTEREDDIRECTORYITERATOR_H_
#include "boost/filesystem.hpp"
#include "boost/regex.hpp"
#include <functional>
template <class NonFilteredIterator = boost::filesystem::directory_iterator>
class FilteredDirectoryIteratorTmpl
: public std::iterator<
std::input_iterator_tag, typename NonFilteredIterator::value_type
>
{
private:
typedef std::string string;
typedef boost::filesystem::path path;
typedef
std::function<
bool(const typename NonFilteredIterator::value_type &dirEntry)
>
FilterFunction;
NonFilteredIterator it;
NonFilteredIterator end;
const FilterFunction filter;
public:
FilteredDirectoryIteratorTmpl();
FilteredDirectoryIteratorTmpl(
const path &iteratedDir, const string &regexMask
);
FilteredDirectoryIteratorTmpl(
const path &iteratedDir, const boost::regex &mask
);
FilteredDirectoryIteratorTmpl(
const path &iteratedDir,
const FilterFunction &filter
);
//preincrement
FilteredDirectoryIteratorTmpl<NonFilteredIterator>& operator++() {
for(++it;it!=end && !filter(*it);++it);
return *this;
};
//postincrement
FilteredDirectoryIteratorTmpl<NonFilteredIterator> operator++(int) {
for(++it;it!=end && !filter(*it);++it);
return FilteredDirectoryIteratorTmpl<NonFilteredIterator>(it,filter);
};
const boost::filesystem::directory_entry &operator*() {return *it;};
bool operator!=(const FilteredDirectoryIteratorTmpl<NonFilteredIterator>& other)
{
return it!=other.it;
};
bool operator==(const FilteredDirectoryIteratorTmpl<NonFilteredIterator>& other)
{
return it==other.it;
};
};
typedef
FilteredDirectoryIteratorTmpl<boost::filesystem::directory_iterator>
FilteredDirectoryIterator;
typedef
FilteredDirectoryIteratorTmpl<boost::filesystem::recursive_directory_iterator>
FilteredRecursiveDirectoryIterator;
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl()
: it(),
filter(
[](const boost::filesystem::directory_entry& /*dirEntry*/){return true;}
)
{
}
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl(
const path &iteratedDir,const string &regexMask
)
: FilteredDirectoryIteratorTmpl(iteratedDir, boost::regex(regexMask))
{
}
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl(
const path &iteratedDir,const boost::regex &regexMask
)
: it(NonFilteredIterator(iteratedDir)),
filter(
[regexMask](const boost::filesystem::directory_entry& dirEntry){
using std::endl;
// return false to skip dirEntry if no match
const string filename = dirEntry.path().filename().native();
return boost::regex_match(filename, regexMask);
}
)
{
if (it!=end && !filter(*it)) ++(*this);
}
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl(
const path &iteratedDir, const FilterFunction &filter
)
: it(NonFilteredIterator(iteratedDir)),
filter(filter)
{
if (it!=end && !filter(*it)) ++(*this);
}
#endif
I believe the directory_iterators will only provide all files in a directory. It up to you to filter them as necessary.
The accepted answer did not compile for me even when I used i->path().extension() instead of leaf(). What did work for me was an example from this website. Here's the code, modified, to apply a filter:
vector<string> results;
filesystem::path filepath(fullpath_to_file);
filesystem::directory_iterator it(filepath);
filesystem::directory_iterator end;
const boost::regex filter("myfilter(capturing group)");
BOOST_FOREACH(filesystem::path const &p, make_pair(it, end))
{
if(is_regular_File(p))
{
match_results<string::const_iterator> what;
if (regex_search(it->path().filename().string(), what, pidFileFilter, match_default))
{
string res = what[1];
results.push_back(res);
}
}
}
I'm using Boost version: 1.53.0.
Why we don't all just use glob() and some regex is beyond me.
As mentioned at the end of Julien-L's post QDir is exactly what you want.
https://qt-project.org/doc/qt-5.0/qtcore/qdir.html#QDir-3
I was looking for a solution to this earlier and I think my solution is the simplest
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/exception/all.hpp>
struct dir_filter_iter
: public boost::iterator_facade<
dir_filter_iter,
boost::filesystem::path,
boost::forward_traversal_tag,
boost::filesystem::path
>
{
using path = boost::filesystem::path;
using impl_type = boost::filesystem::directory_iterator;
dir_filter_iter():impl_(){}
dir_filter_iter(path p, boost::regex rgx):impl_(std::move(p)),rgx_(std::move(rgx)){
namespace bf = boost::filesystem;
if( ! bf::is_directory(p) ){
BOOST_THROW_EXCEPTION(
boost::enable_error_info(std::domain_error("not a dir"))
<< boost::errinfo_file_name(p.string()));
}
//advance to first matching item if impl_ is not already at end()
if(impl_ != impl_type()) {
std::string s(impl_->path().string());
if( !boost::regex_match( s, rgx_ )) increment();
}
}
private:
friend class boost::iterator_core_access;
bool equal(const dir_filter_iter& that)const{
return this->impl_ == that.impl_;
}
void increment(){
assert( impl_ != impl_type() );
for(;;){
++impl_;
if( impl_ == impl_type() )
break;
std::string s(impl_->path().string());
if( boost::regex_match( s, rgx_ ) ){
break;
}
}
}
path dereference()const{
assert( impl_ != impl_type() );
return *impl_;
}
impl_type impl_;
boost::regex rgx_;
};
struct dir_filter_iter_maker{
using value_type = dir_filter_iter;
explicit dir_filter_iter_maker(boost::regex rgx):rgx_(rgx){}
value_type make()const{
return value_type();
}
value_type make(boost::filesystem::path p)const{
return value_type(std::move(p),rgx_);
}
template<typename... Args>
auto operator()(Args&&... args)->decltype(make(args...)){
return this->make(std::forward<Args>(args)...);
}
private:
boost::regex rgx_;
};
Then you can do
dir_filter_iter_maker di_maker(boost::regex(R"_(.*\.hpp)_"));
std::for_each( di_maker(p), di_maker(), [](const bf::path& p){std::cout << p.string() << "\n";});

How to define an common iterator to my class hirerachy

My team designed a library meant to store data from different "signals". A signal is a list of timestamped float values. We have three way to store a signal (depending of the way it was recorded from the hardware in the first place):
MarkerSignal: We store a sorted std::vector of std::pair of (boost::posix_time::ptime,float)
RawSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration) and finally a std::vector of float (each value's timestamp is start time + period * value's index in the vector)
NumericalSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration), a scale (float), an offset (float) and finally a std::vector of short (timestamp is computed as for RawSignal and float value is short*scale+offset)
Those three signals have a common parent class (SignalBase) storing the signal's name, description, unit and stuff like that. We use the visitor pattern to let people nicely "cast" the SignalBase to a MarkerSignal/RawSignal/NumericalSignal and then access the data it contains.
In the end, what we need for each class is to iterate through all elements, one element being actually a pair of (boost::posix_time::ptime,float) (like MarkerSignal). And it's a pain having to create a visitor every time we want to do that.
Storing all signals as a std::vector<std::pair<boost::posix_time::ptime,float>> (or returning an object of this kind on demand) uses too much memory.
We thought the best was probably to define our own iterator object. The iterator would give access to the timestamp and value, like that:
SignalBase* signal = <any signal>;
for ( SignalBase::iterator iter = signal->begin();
iter != signal->end();
++iter )
{
boost::posix_time::ptime timestamp = iter.time();
float value = iter.value();
}
What's the best approach/strategy to create such an iterator class? (simple class with a size_t index attribute, or a MarkerSignal/RawSignal/NumericalSignal container's specific iterator as attribute, store a std::pair<boost::posix_time::ptime,float> and update it from a ++ operator...).
Also, I would much prefer if the solution rpoposed avoids using a virtual table (to have ++, time(), and value() be faster when iterating on huge signals).
To sum up I think the best you can achieve if you value for efficiency could be something like this:
template <typename SignalType, typename Functor = function<void(typename SignalType::value_type&&) > >
void iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
Then for call:
iterateThroughSignal<MarkerSignal>(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
I'm not sure if you are using C++11 so the lambda can be replace by function pointer, rvalue reference using lvalue reference and the std::function with a function signature...
Edit:
To make it compile when the type of the foo signature won't match the SignalType::value_type there will be a need of playing a little bit with sfinae:
template <typename SignalType>
class IterateHelper {
template <typename Functor>
static typename enable_if<first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
template <typename Functor>
static typename enable_if<!first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
}
};
I leave the implementation of first_param_is helper struct to you... Call would change to:
IteratorHelper<MarkerSignal>::iterateThroughSignal(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
As I wanted something easy to use for people using my library (be able to esily do a for loop) I finally implemented my own iterator like that:
Added two virtual functions in SignalBase (found no alternative to that, runtime will use the virtual table):
virtual size_t floatDataCount() const = 0;
virtual bool loadFloatInfoAt( size_t pos, SignalFloatIter::ValueInfo& info ) const = 0;
Added functions in SignalBase to get begin/end iterators:
inline BDL::SignalFloatIter beginFloatIter() const { return BDL::SignalFloatIter::beginIter( *this ); }
inline BDL::SignalFloatIter endFloatIter() const { return BDL::SignalFloatIter::endIter( *this ); }
Declared iterator class like that:
class SignalFloatIter
{
public:
SignalFloatIter( const SignalBase* signal = NULL, size_t pos = 0 );
SignalFloatIter( const SignalFloatIter& iter );
static SignalFloatIter beginIter( const SignalBase& signal );
static SignalFloatIter endIter( const SignalBase& signal );
SignalFloatIter& operator=( const SignalFloatIter& iter );
bool operator==( const SignalFloatIter& iter ) const;
bool operator!=( const SignalFloatIter& iter ) const;
/** Pre-increment operator */
SignalFloatIter& operator++();
/** Post-increment operator */
SignalFloatIter operator++(int unused);
inline const BDL::time& when() const { assert( m_valid ); return m_info.first.first; }
inline const BDL::duration& duration() const { assert( m_valid ); return m_info.first.second; }
inline const float& value() const { assert( m_valid ); return m_info.second; }
inline size_t index() const { assert( m_valid ); return m_pos; }
inline BDL::MarkerKey markerKey() const { assert( m_valid ); return std::make_pair( when(), duration() ); }
inline bool valid() const { return m_valid; }
typedef std::pair<BDL::time,BDL::duration> TimeInfo;
typedef std::pair<TimeInfo,float> ValueInfo;
private:
const SignalBase* m_signal;
size_t m_pos;
bool m_valid;
ValueInfo m_info;
void loadCurInfo();
};
Implemented:
SignalFloatIter::SignalFloatIter( const SignalBase* signal, size_t pos ) :
m_signal( signal ),
m_pos( pos )
{
loadCurInfo();
}
SignalFloatIter::SignalFloatIter( const SignalFloatIter& iter )
{
operator=( iter );
}
SignalFloatIter SignalFloatIter::beginIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, 0 );
}
SignalFloatIter SignalFloatIter::endIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, signal.floatDataCount() );
}
SignalFloatIter& SignalFloatIter::operator=( const SignalFloatIter& iter )
{
if ( this != &iter )
{
m_signal = iter.m_signal;
m_pos = iter.m_pos;
m_info = iter.m_info;
m_valid = iter.m_valid;
}
return *this;
}
bool SignalFloatIter::operator==( const SignalFloatIter& iter ) const
{
if ( m_signal == iter.m_signal )
{
if ( m_pos == iter.m_pos )
{
assert( m_valid == iter.m_valid );
if ( m_valid )
assert( m_info == iter.m_info );
return true;
}
else
{
return false;
}
}
else
{
assert( false );
return false;
}
}
bool SignalFloatIter::operator!=( const SignalFloatIter& iter ) const
{
return !( *this == iter );
}
SignalFloatIter& SignalFloatIter::operator++()
{
++m_pos;
loadCurInfo();
return *this;
}
SignalFloatIter SignalFloatIter::operator++( int unused )
{
SignalFloatIter old = *this;
assert( unused == 0 ); // see http://en.cppreference.com/w/cpp/language/operator_incdec
++m_pos;
loadCurInfo();
return old;
}
void SignalFloatIter::loadCurInfo()
{
if ( m_signal )
{
m_valid = m_signal->loadFloatInfoAt( m_pos, m_info );
}
else
{
assert( false );
m_valid = false;
}
}
It's pretty straightforward and easy to use for any signal:
std::cout << "Signal timestamped data are: ";
for ( BDL::SignalFloatIter iter = signal.beginFloatIter();
iter != signal.endFloatIter();
++iter )
{
std::cout << iter.when() << " : " << iter.value() << std::endl;
}

Search in a vector of structs

I have a vector full with structs look like this
struct person_t
{
string name;
string id;
struct location_t location;
};
vector <person_t> myvector;
and i have read in the items in myvector
but now i need to know how to search for specific item in vector and count how many of that item it is in the vector.
unsigned int count = std::count_if( myvector.begin(), myvector.begin(),
[]( const person_t & p ) { return p.name == "Bill Gates"; }
);
or without c++11
struct EqualByName {
EqualByName( const std::string & name ) : m_name( name ) {}
bool operator()( const person_t & p ) const { return p.name == m_name; }
private:
std::string m_name;
};
unsigned int count = std::count_if( myvector.begin(), myvector.begin(),
EqualByName( "Bill Gates" )
);
or ugly looking but for all occasions ))
template< class T, class FieldType, FieldType T::*FieldPtr >
struct EqualBy
{
EqualBy( const FieldType & value ) : m_fieldValue( value ) {}
bool operator()( const T & r ) const {
return m_fieldValue == r.*FieldPtr;
}
bool operator()( const T * p ) const {
return m_fieldValue == p->*FieldPtr;
}
private:
const FieldType m_fieldValue;
};
// usage:
typedef EqualBy< person_t, std::string, & person_t::name > EqualByName;
typedef EqualBy< person_t, std::string, & person_t::id > EqualById;
unsigned int namesCount = std::count_if( myvector.begin(), myvector.end(),
EqualByName( "Bill Gates" )
);
unsigned int idsCount = std::count_if( myvector.begin(), myvector.end(),
EqualById( "123456" )
);

C++ tree output error

for my data structures class, we are making a data structure that we can use to easily store and organize data. I am having an issue with the output function of my tree. The error message that I get is:
AccountDB.cpp: In member function ‘void AccountDB::output(std::ostream&) const’:
AccountDB.cpp:23:21: error: passing ‘const AccountDB’ as ‘this’ argument of ‘void
AccountDB::output(std::ostream&, const AccountDB::Elem*)’ discards qualifiers [-fpermissive]
I've been looking around and my output code looks pretty similar to what other people have done. I have no idea, and I don't really understand what the error is trying to tell.
Thanks for your help.
Header:
#ifndef ACCOUNTDB_H
#define ACCOUNTDB_H
#include <iostream>
using namespace std;
#include "AccountRecord.h"
class AccountDB {
public:
AccountDB();
~AccountDB();
void insert( const AccountRecord &v );
AccountRecord * get( const AccountRecord &v );
void output( ostream &s ) const;
private:
struct Elem {
AccountRecord info;
Elem *left;
Elem *right;
};
Elem *root;
void insert( const AccountRecord &v, Elem *&e );
AccountRecord * get( const AccountRecord &v, Elem *&e );
void output( ostream &s, const Elem *e );
};
ostream &operator << ( ostream &s, const AccountDB &v );
#endif
Source
#include "AccountDB.h"
//default constructor
AccountDB::AccountDB() {
root = 0;
}
//destructor
AccountDB::~AccountDB() {
}
//public
void AccountDB::insert( const AccountRecord &v ) {
return insert( v, root );
}
AccountRecord * AccountDB::get( const AccountRecord &v ) {
return get( v, root );
}
void AccountDB::output( ostream &s ) const {
output( s, root );
}
//private
void AccountDB::insert( const AccountRecord &v, Elem *&e ) {
if( e == NULL ) {
e = new Elem();
e->info = v;
}
else if( v < e->info )
insert( v, e->left );
else if( v > e->info )
insert( v, e->right );
}
AccountRecord * AccountDB::get( const AccountRecord &v, Elem *&e ){
if( e->info == v )
return &(e->info);
else if( v < e->info && e->left != NULL )
get( v, e->left );
else if( v > e->info && e->right != NULL )
get( v, e-> right );
else
return NULL;
}
void AccountDB::output( ostream &s, const Elem *e ) {
if( e != NULL ) {
output( s, e->left );
s << e->info << endl;
output( s, e->right );
}
}
ostream &operator << ( ostream &s, const AccountDB &v ) {
v.output( s );
return s;
}
Your output function is not declared const, so when you call
output( s, root );
the compiler tells you that you are calling a non-const function from inside a const function.
There are several ways to deal with this - one is to make output const; the other is to make output static (if you can).
The error is that
void AccountDB::output( ostream &s, const Elem *e )
is not declared as const, but you call it from a const method.
Change the declaration (and definition) to:
void output( ostream &s, const Elem *e ) const;
You can do this since you're not modifying any members inside the function.

Can I use a mask to iterate files in a directory with Boost?

I want to iterate over all files in a directory matching something like somefiles*.txt.
Does boost::filesystem have something built in to do that, or do I need a regex or something against each leaf()?
EDIT: As noted in the comments, the code below is valid for versions of boost::filesystem prior to v3. For v3, refer to the suggestions in the comments.
boost::filesystem does not have wildcard search, you have to filter files yourself.
This is a code sample extracting the content of a directory with a boost::filesystem's directory_iterator and filtering it with boost::regex:
const std::string target_path( "/my/directory/" );
const boost::regex my_filter( "somefiles.*\.txt" );
std::vector< std::string > all_matching_files;
boost::filesystem::directory_iterator end_itr; // Default ctor yields past-the-end
for( boost::filesystem::directory_iterator i( target_path ); i != end_itr; ++i )
{
// Skip if not a file
if( !boost::filesystem::is_regular_file( i->status() ) ) continue;
boost::smatch what;
// Skip if no match for V2:
if( !boost::regex_match( i->leaf(), what, my_filter ) ) continue;
// For V3:
//if( !boost::regex_match( i->path().filename().string(), what, my_filter ) ) continue;
// File matches, store it
all_matching_files.push_back( i->leaf() );
}
(If you are looking for a ready-to-use class with builtin directory filtering, have a look at Qt's QDir.)
There is a Boost Range Adaptors way:
#define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
#include <boost/filesystem.hpp>
#include <boost/range/adaptors.hpp>
namespace bfs = boost::filesystem;
namespace ba = boost::adaptors;
const std::string target_path( "/my/directory/" );
const boost::regex my_filter( "somefiles.*\.txt" );
boost::smatch what;
for (auto &entry: boost::make_iterator_range(bfs::directory_iterator(target_path), {})
| ba::filtered(static_cast<bool (*)(const bfs::path &)>(&bfs::is_regular_file))
| ba::filtered([&](const bfs::path &path){ return boost::regex_match(path.filename().string(), what, my_filter); })
)
{
// There are only files matching defined pattern "somefiles*.txt".
std::cout << entry.path().filename() << std::endl;
}
My solution is essentially the same as Julien-L, but encapsulated in the include file it is nicer to use. Implemented using boost::filesystem v3. I guess that something like that is not included in the boost::filesystem directly because it would introduce dependency on boost::regex.
#include "FilteredDirectoryIterator.h"
std::vector< std::string > all_matching_files;
std::for_each(
FilteredDirectoryIterator("/my/directory","somefiles.*\.txt"),
FilteredDirectoryIterator(),
[&all_matching_files](const FilteredDirectoryIterator::value_type &dirEntry){
all_matching_files.push_back(dirEntry.path());
}
);
alternatively use FilteredRecursiveDirectoryIterator for recursive sub directories search:
#include "FilteredDirectoryIterator.h"
std::vector< std::string > all_matching_files;
std::for_each(
FilteredRecursiveDirectoryIterator("/my/directory","somefiles.*\.txt"),
FilteredRecursiveDirectoryIterator(),
[&all_matching_files](const FilteredRecursiveDirectoryIterator::value_type &dirEntry){
all_matching_files.push_back(dirEntry.path());
}
);
FilteredDirectoryIterator.h
#ifndef TOOLS_BOOST_FILESYSTEM_FILTEREDDIRECTORYITERATOR_H_
#define TOOLS_BOOST_FILESYSTEM_FILTEREDDIRECTORYITERATOR_H_
#include "boost/filesystem.hpp"
#include "boost/regex.hpp"
#include <functional>
template <class NonFilteredIterator = boost::filesystem::directory_iterator>
class FilteredDirectoryIteratorTmpl
: public std::iterator<
std::input_iterator_tag, typename NonFilteredIterator::value_type
>
{
private:
typedef std::string string;
typedef boost::filesystem::path path;
typedef
std::function<
bool(const typename NonFilteredIterator::value_type &dirEntry)
>
FilterFunction;
NonFilteredIterator it;
NonFilteredIterator end;
const FilterFunction filter;
public:
FilteredDirectoryIteratorTmpl();
FilteredDirectoryIteratorTmpl(
const path &iteratedDir, const string &regexMask
);
FilteredDirectoryIteratorTmpl(
const path &iteratedDir, const boost::regex &mask
);
FilteredDirectoryIteratorTmpl(
const path &iteratedDir,
const FilterFunction &filter
);
//preincrement
FilteredDirectoryIteratorTmpl<NonFilteredIterator>& operator++() {
for(++it;it!=end && !filter(*it);++it);
return *this;
};
//postincrement
FilteredDirectoryIteratorTmpl<NonFilteredIterator> operator++(int) {
for(++it;it!=end && !filter(*it);++it);
return FilteredDirectoryIteratorTmpl<NonFilteredIterator>(it,filter);
};
const boost::filesystem::directory_entry &operator*() {return *it;};
bool operator!=(const FilteredDirectoryIteratorTmpl<NonFilteredIterator>& other)
{
return it!=other.it;
};
bool operator==(const FilteredDirectoryIteratorTmpl<NonFilteredIterator>& other)
{
return it==other.it;
};
};
typedef
FilteredDirectoryIteratorTmpl<boost::filesystem::directory_iterator>
FilteredDirectoryIterator;
typedef
FilteredDirectoryIteratorTmpl<boost::filesystem::recursive_directory_iterator>
FilteredRecursiveDirectoryIterator;
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl()
: it(),
filter(
[](const boost::filesystem::directory_entry& /*dirEntry*/){return true;}
)
{
}
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl(
const path &iteratedDir,const string &regexMask
)
: FilteredDirectoryIteratorTmpl(iteratedDir, boost::regex(regexMask))
{
}
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl(
const path &iteratedDir,const boost::regex &regexMask
)
: it(NonFilteredIterator(iteratedDir)),
filter(
[regexMask](const boost::filesystem::directory_entry& dirEntry){
using std::endl;
// return false to skip dirEntry if no match
const string filename = dirEntry.path().filename().native();
return boost::regex_match(filename, regexMask);
}
)
{
if (it!=end && !filter(*it)) ++(*this);
}
template <class NonFilteredIterator>
FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl(
const path &iteratedDir, const FilterFunction &filter
)
: it(NonFilteredIterator(iteratedDir)),
filter(filter)
{
if (it!=end && !filter(*it)) ++(*this);
}
#endif
I believe the directory_iterators will only provide all files in a directory. It up to you to filter them as necessary.
The accepted answer did not compile for me even when I used i->path().extension() instead of leaf(). What did work for me was an example from this website. Here's the code, modified, to apply a filter:
vector<string> results;
filesystem::path filepath(fullpath_to_file);
filesystem::directory_iterator it(filepath);
filesystem::directory_iterator end;
const boost::regex filter("myfilter(capturing group)");
BOOST_FOREACH(filesystem::path const &p, make_pair(it, end))
{
if(is_regular_File(p))
{
match_results<string::const_iterator> what;
if (regex_search(it->path().filename().string(), what, pidFileFilter, match_default))
{
string res = what[1];
results.push_back(res);
}
}
}
I'm using Boost version: 1.53.0.
Why we don't all just use glob() and some regex is beyond me.
As mentioned at the end of Julien-L's post QDir is exactly what you want.
https://qt-project.org/doc/qt-5.0/qtcore/qdir.html#QDir-3
I was looking for a solution to this earlier and I think my solution is the simplest
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/exception/all.hpp>
struct dir_filter_iter
: public boost::iterator_facade<
dir_filter_iter,
boost::filesystem::path,
boost::forward_traversal_tag,
boost::filesystem::path
>
{
using path = boost::filesystem::path;
using impl_type = boost::filesystem::directory_iterator;
dir_filter_iter():impl_(){}
dir_filter_iter(path p, boost::regex rgx):impl_(std::move(p)),rgx_(std::move(rgx)){
namespace bf = boost::filesystem;
if( ! bf::is_directory(p) ){
BOOST_THROW_EXCEPTION(
boost::enable_error_info(std::domain_error("not a dir"))
<< boost::errinfo_file_name(p.string()));
}
//advance to first matching item if impl_ is not already at end()
if(impl_ != impl_type()) {
std::string s(impl_->path().string());
if( !boost::regex_match( s, rgx_ )) increment();
}
}
private:
friend class boost::iterator_core_access;
bool equal(const dir_filter_iter& that)const{
return this->impl_ == that.impl_;
}
void increment(){
assert( impl_ != impl_type() );
for(;;){
++impl_;
if( impl_ == impl_type() )
break;
std::string s(impl_->path().string());
if( boost::regex_match( s, rgx_ ) ){
break;
}
}
}
path dereference()const{
assert( impl_ != impl_type() );
return *impl_;
}
impl_type impl_;
boost::regex rgx_;
};
struct dir_filter_iter_maker{
using value_type = dir_filter_iter;
explicit dir_filter_iter_maker(boost::regex rgx):rgx_(rgx){}
value_type make()const{
return value_type();
}
value_type make(boost::filesystem::path p)const{
return value_type(std::move(p),rgx_);
}
template<typename... Args>
auto operator()(Args&&... args)->decltype(make(args...)){
return this->make(std::forward<Args>(args)...);
}
private:
boost::regex rgx_;
};
Then you can do
dir_filter_iter_maker di_maker(boost::regex(R"_(.*\.hpp)_"));
std::for_each( di_maker(p), di_maker(), [](const bf::path& p){std::cout << p.string() << "\n";});