очередное тестовое задание
От: nen777w  
Дата: 01.12.14 14:23
Оценка: :)
Во общем очередное тестовое задание, от немецкой софтверной компании.
Фитбека не дали, кроме как мы посовещались и решили что вы нам не походите, поэтому не считаю что не могу так поступить.
Тем более что не оговаривали то что задание не распостранять (хотя я немного изменил его что бы не было понятно из какой конторы).

  "Итак ТЗ"

C++ Template:

class MyClass
{
public:
 getBmCount(...)
 {
 }
 replaceBmWithBM(...)
 {
 }
};

int main()
{
 const char *szTestString1 = "Bm bM BM bM Bm";
 const wchar_t *szTestString2 = L"Bm bM BM bM Bm";
 // Invoke getBmCount(...) of class MyClass
 // Invoke replaceBmWithBM(...) of class MyClass
 // Display on screen: "Found X occurrences of Bm. New string: Y"
}


Task description:
1. Implement the two functions getBmCount and replaceBmWithBM of the class MyClass:
— getBmCount should return the number of occurrences of "Bm" within szTestString1/2 (case sensitive)
— replaceBmWithBM should replace all occurrences of "Bm" in szTestString1/2 with "BM" (case sensitive)
2. Invoke the two functions getBmCount and replaceBmWithBM.
3. Display the string given in the last comment on screen. X and Y should be replaced with the real values.
4. The class MyClass should be able to deal with both szTestString1 (ASCII) and szTestString2 (Unicode).
General requirements:
The code should be
— easy to understand and maintain (Priority 1)
— technically elegant (Priority 2)
— as (CPU) efficient as possible (Priority 3)
You’re allowed to use all technics, toolkits and frameworks which are based on the C++ language.



  "Реализация:"
/*
 * Ruslan Teliuk test task.
*/


#include <string.h> 
#include <iterator>
#include <iostream>
#include <conio.h>
#include <assert.h>
#if defined(_MSC_VER)
    #include <string> //for getline
#endif


namespace helper_functions 
{
    template<typename T> struct assert_false : public std::false_type {};

    template<typename CharType> 
    size_t string_length(const CharType*) { 
        static_assert(assert_false<CharType>::value, "Illegal template instantiation sds"); 
        return 0; 
    }

    template<> 
    size_t string_length<char>(const char *str) { return strlen(str); }

    template<> 
    size_t string_length<wchar_t>(const wchar_t *str) { return wcslen(str); }
}

//..........................................................................................................

class MyClass
{
public: //Core Algorithm's
    enum e_predicate_result {
          //should return when input is not match to pattern
          eNotMatch
          //should return when input is separator
        , eSeparator
          //should return when input is partially match to pattern 
        , eMatch
          //should return when input is full match to pattern
        , eFullMatch
    };

    //..........................................................................................................

    template<typename Iter, typename Pred>
    static size_t count_of_patterns(Iter begin_, Iter end_, Pred pr_)
    {
        size_t result = 0;
        enum e_state { stWaitForBegin, stMatch, stWaitForMatch, stWaitForEnd };

        e_state state = stWaitForMatch;
        e_predicate_result cl = eNotMatch;

        while(begin_ != end_)
        {
            cl = pr_(*begin_);

            switch(cl)
            {
            case eNotMatch:
                {
                    state = stWaitForBegin;
                } break;
            case eMatch:
                {
                    switch(state)
                    {
                    case stWaitForEnd:
                        state = stWaitForBegin;
                        break;
                    case stWaitForBegin:
                        break;
                    default:
                        state = stMatch;
                    }
                } break;
            case eFullMatch:
                {
                    if(stWaitForBegin != state) {
                        state = stWaitForEnd;
                    }
                } break;
            case eSeparator:
                {
                    switch(state)
                    {
                    case stWaitForEnd:
                        {
                            result++;
                            state = stWaitForMatch;
                        } break;
                    case stWaitForBegin:
                        {
                            state = stWaitForMatch;
                        } break;
                    }
                } break;
            }

            begin_++;
        }

        if(stWaitForEnd == state && eFullMatch == cl) {
            ++result;
        }

        return result;
    }

    //..........................................................................................................

    template<typename Iter, typename CIter, typename Pred>
    static size_t substitute_pattern(Iter begin_, Iter end_, CIter patt_begin_, CIter patt_end_, CIter repl_begin_, CIter repl_end_, Pred pr_)
    {
        if(std::distance(patt_begin_, patt_end_) != std::distance(repl_begin_, repl_end_)) return 0;

        size_t total_substitutions = 0;
        Iter replace_point = end_;

        enum e_state { stWaitForBegin, stMatch, stWaitForMatch, stWaitForEnd };

        e_state state = stWaitForMatch;
        e_predicate_result cl = eNotMatch;

        while(begin_ != end_)
        {
            cl = pr_(*begin_);

            switch(cl)
            {
            case eNotMatch:
                {
                    state = stWaitForBegin;
                    replace_point = end_;
                } break;
            case eMatch:
                {
                    switch(state)
                    {
                    case stWaitForEnd:
                        state = stWaitForBegin;
                        break;
                    case stWaitForBegin:
                        break;
                    default:
                        state = stMatch;
                        if(end_ == replace_point) {
                            replace_point = begin_;
                        }
                    }
                } break;
            case eFullMatch:
                {
                    if(stWaitForBegin != state) {
                        state = stWaitForEnd;
                    }
                } break;
            case eSeparator:
                {
                    switch(state)
                    {
                    case stWaitForEnd:
                        {
                            state = stWaitForMatch;

                            CIter it = repl_begin_;
                            while(repl_end_ != it) {
                                *replace_point++ = *it++;
                            }
                            replace_point = end_;
                            total_substitutions++;
                        } break;
                    case stWaitForBegin:
                        {
                            state = stWaitForMatch;
                        } break;
                    }
                } break;
            }

            begin_++;
        }

        if(stWaitForEnd == state && eFullMatch == cl) {
            CIter it = repl_begin_;
            while(repl_end_ != it) {
                *replace_point++ = *it++;
            }
            ++total_substitutions;
        }

        return total_substitutions;
    }

private: //General calls
    template<typename CharType>
    static size_t getCount(const CharType *str, const CharType *pattern, CharType separator)
    {
        using namespace helper_functions;

        const CharType *pb = pattern, *pe = pattern + string_length(pattern);
        return count_of_patterns(str, str+string_length(str), [pattern, &pb, pe, separator](CharType c) -> e_predicate_result
            {
                if(c == *pb)
                {
                    ++pb;
                    if(pb == pe) {
                        pb = pattern;
                        return eFullMatch;
                    }

                    return eMatch;
                }

                pb = pattern;
                return separator == c ? eSeparator : eNotMatch;
            }
        );
    }

    //..........................................................................................................

    template<typename CharType>
    static size_t replaceWith(CharType *str, const CharType *from, const CharType *to, CharType separator)
    {
        using namespace helper_functions;

        const CharType *pb = from, *pe = from + string_length(from);
        return substitute_pattern(str, str+string_length(str), from, from+string_length(from), to, to+string_length(to), [from, &pb, pe, separator](CharType c) -> e_predicate_result 
            {
                if(c == *pb)
                {
                    ++pb;
                    if(pb == pe) {
                        pb = from;
                        return eFullMatch;
                    }

                    return eMatch;
                }

                pb = from;
                return separator == c ? eSeparator : eNotMatch;
            }
        );
    }

public: //Calls from test task
    static size_t getBmCount(const char *str)
    {
        return getCount(str, "Bm", ' ');
    }

    static size_t getBmCount(const wchar_t *str)
    {
        return getCount(str, L"Bm", L' ');
    }

    static size_t replaceBmWithBM(char *str)
    {
        return replaceWith(str, "Bm", "BM", ' ');
    }

    static size_t replaceBmWithBM(wchar_t *str)
    {
        return replaceWith(str, L"Bm", L"BM", L' ');
    }
};

/*
    DESCRIPTION (1. Implement the two functions getBmCount and replaceBmWithBM of the class MyClass):

    The core algorithms from the test task implemented in ("Core Algorithm's" section):

    template<typename Iter, typename Pred>
    static size_t count_of_patterns(Iter begin_, Iter end_, Pred pr_)

    and 

    template<typename Iter, typename CIter, typename Pred>
    static size_t substitute_pattern(Iter begin_, Iter end_, CIter patt_begin_, CIter patt_end_, CIter repl_begin_, CIter repl_end_, Pred pr_)

    It can be used with raw pointer and with iterators for example std::w/string::iterator.
    The predicate function should define the pattern matching and return enum e_predicate_result
    It allow a more flexible lookup/replace patterns from the input source even if it should contain the same symbol which is using for separator.

    The example functors implementation in "General calls" section:
    
    template<typename CharType>
    static size_t getCount(const CharType *str, const CharType *pattern, CharType separator)

    and

    template<typename CharType>
    static size_t replaceWith(CharType *str, const CharType *from, const CharType *to, CharType separator)
*/

int main(int /*argc*/, char** /*argv*/)
{
    /*
        DESCRIPTION (2. Implement the two functions getBmCount and replaceBmWithBM of the class MyClass):
        I replaced the const char/wchar_t * to char/wchar_t[] for allow implace data modifed in replaceXXX functions.
        Sorry if I miss misunderstood  the test task wrong and replaceXXX functions should return copy of string
        If need I can fix it.
    */

    char szTestString1[] = "Bm bM BM bM Bm";
    wchar_t szTestString2[] = L"Bm bM BM bM Bm";

    size_t nBmCountASCII = MyClass::getBmCount(szTestString1);
    size_t nBmCountUNICODE = MyClass::getBmCount(szTestString2);

    size_t nNumberOfReplacesASCII = MyClass::replaceBmWithBM(szTestString1);
    size_t nNumberOfReplacesUNICODE = MyClass::replaceBmWithBM(szTestString2);

    /*
        DESCRIPTION (3. Display the string given in the last comment on screen. X and Y should be replaced with the real values.):
        If I understand correctly the Y it's a input from user.
    */

    std::string Y;
    getline(std::cin, Y);

    std::cout << "Found " << MyClass::getBmCount(Y.c_str()) << " occurrences of Bm. New string: " << Y;
    

    //for pause
    getch();

    return 0;
}


Буду благодарен за фитбеки.
Компиляция: g++ -std=c++11 -lstdc++ test.cpp -otest.exe
Отредактировано 01.12.2014 14:28 nen777w . Предыдущая версия . Еще …
Отредактировано 01.12.2014 14:23 nen777w . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.