Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I want to simulate in c++ the fact that in a form with drop down (or combo boxes) you can filter by selecting items and then projecting on a given set of properties for these item.

In a sql-like query it could be

select age, name 
from (select * from table t where isoncodereview = true )
where country = "US";

I have come up with the a template class with template parameters:

The complete declaration of the class is

template<class K, class T> class IterativeSettingFilter
{
public:

    IterativeSettingFilter(){}

    std::vector<T>& originalSet()
    {
        return _origset;
    }

    const std::vector<T>& currentSet() const
    {
        return history.empty() ? _origset : history.back().second;
    }

    void reset()
    {
        history.clear();
        indexByKey.clear();
    }

    template <class predicateFilter>
    bool applyCondition(const K& id, const predicateFilter& customfilter)
    {
        std::vector<T> nextSet;
        std::copy_if(currentSet().begin(), currentSet().end(), std::back_inserter(nextSet), customfilter);

        indexByKey.insert( std::make_pair(id, history.size()) );
        history.push_back(std::make_pair(id, nextSet));

        return true;
    }

    std::vector<T> setAt(const K& id) const
    {
        auto it = indexByKey.find(id);
        if(it == indexByKey.end())
            return std::vector<T>();

        size_t index = it->second;
        return history[index];
    }

    bool rollBackBeforeCondition(const K& id)
    {
        if(id == defaultid)
        {
            reset();
            return true;
        }
        auto it = indexByKey.find(id);
        if(it == indexByKey.end())
            return false;

        size_t index = it->second;
        while( !history.empty() && history.size() > index)//size might be linear with list before c++11
        {
            indexByKey.erase(history.back().first);
            history.pop_back();
        }
        return true;
    }

    template <class E, class Projection>
    std::set<E> project(const Projection& projection) const
    {
        std::set<E> projected;
        std::transform(currentSet().begin(), currentSet().end(), std::inserter(projected, projected.end()), projection);
        return projected;
    }

    template <class E, class Projection>
    std::set<E> project(const K& id, const Projection& projection) const
    {
        std::set<E> projected;
        const std::vector<T>& selectedVect = correspondingSet(id); 
        std::transform(selectedVect.begin(), selectedVect.end(), std::inserter(projected, projected.end()), projection);
        return projected;
    }

    K predecessor(const K& id) const
    {
        auto iter = indexByKey.find(id);
        if( iter != indexByKey.end() )
        {
            size_t pos = iter->second;
            return pos == 0 ? defaultid : history.at(pos - 1).first;
        }
        else
        {
            return history.empty() ? defaultid : history.back().first;
        }
    }

private:

    const std::vector<T>& correspondingSet(const K& id) const
    {
        if(id == defaultid )
        {
            return  _origset;
        }
        else
        {
            auto iter = indexByKey.find(id);
            if( iter != indexByKey.end() )
            {
                size_t pos = iter->second;
                return history.at(pos).second;
            }
            else
            {
                return currentSet();
            }
        }
    }

private:
    K defaultid;
    std::vector<T> _origset;

    std::vector< std::pair< K, std::vector<T> > > history;
    std::map< K, size_t > indexByKey;

public:
    // http://en.cppreference.com/w/cpp/concept/Swappable
    void swap(IterativeSettingFilter& other) 
    {
        swap(defaultid, other.defaultid);
        swap(_origset,  other._origset);
        swap(history,   other.history);
        swap(indexByKey,other.indexByKey)
    }
};

So You can apply as many filters, to obtain an ordered list of generations. For any generation you can project on a given property to obtain a unique set. Can I improved the performance, clarity or design? Are there better standard collection than the one I used?

share|improve this question
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.