Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
 
Эксперт С++
8421 / 3954 / 866
Регистрация: 15.11.2014
Сообщений: 8,904
1

[с++][дизайн][сложность] обсуждение

18.10.2017, 19:25. Показов 481. Ответов 10

всем привет.


рассмотрим код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#pragma once
 
#include <tools/text.h>
#include <cassert>
 
#define dTOOLS_MATCH_PATTERN_USED_ ::tools
 
namespace tools{
 
    template<class s1, class s2>
    bool match_pattern(const s1& value, const s2& mask) 
    {
        drequired_stringed(s1, value);
        drequired_stringed(s2, mask );
        drequired_compatible(s1, value, s2, mask);
 
        assert(dMYTEXT::valid(value));
        assert(dMYTEXT::valid(mask));
 
        dSTDSTRING(s1) ss(value);
        dSTDSTRING(s2) pp(mask );
 
        using ch = dMYTEXT::character<s1>;
 
        ch* s = &ss[0];
        ch* p = &pp[0];
 
        ch *rs=0, *rp=0;
        while(true)
            if(*p=='*')
                rs=s, rp=++p;
            else if(!*s)
                return !*p;
            else if(*s==*p || *p=='?')
                ++s, ++p;
            else if(rs)
                s=++rs, p=rp;
            else
                return false;
    }
это функция сравнения текстового имени по файловой маске.
и кода вроде бы не много.
и выглядит он не особо сложно.

более того - код эффективен.
быстро работает.
а засчет шаблоно-природы
компилятор будет генерировать эффективный код
для любых входных аргументов.

функция без изменений может работать с любыми стрингообразными:
массивы/указатели/классы-строки

на самом деле собака зарыта в хедере:
C++
1
#include <tools/text.h>
он тянет за собой достаточно нетривиальный код,
что бы можно было в компалтайме обрабатывть любые строки.

то есть, за эффективность и универсальность
приходится платить сложностью.


рассмотрим альтернативу:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    inline bool match_pattern(const char* value, const char* mask) 
    {
        assert(value);
        assert(mask );
 
        std::string ss(value);
        std::string pp(mask );
 
        using ch = char;
 
        ch* s = &ss[0];
        ch* p = &pp[0];
 
        ch *rs=0, *rp=0;
        while(true)
            if(*p=='*')
                rs=s, rp=++p;
            else if(!*s)
                return !*p;
            else if(*s==*p || *p=='?')
                ++s, ++p;
            else if(rs)
                s=++rs, p=rp;
            else
                return false;
    }
    inline bool match_pattern(const std::string& value, const char* mask)
        { return match_pattern(value.c_str(), mask); }
 
    inline bool match_pattern(const char* value, const std::string& mask)
        { return match_pattern(value, mask.c_str()); }
 
    inline bool match_pattern(const std::string& value, const std::string& mask)
        { return match_pattern(value.c_str(), mask.c_str()); }
 
//==============================================================================
//==============================================================================
 
    inline bool match_pattern(const wchar_t* value, const wchar_t* mask) 
    {
        assert(value);
        assert(mask );
 
        std::wstring ss(value);
        std::wstring pp(mask );
 
        using ch = wchar_t;
 
        ch* s = &ss[0];
        ch* p = &pp[0];
 
        ch *rs=0, *rp=0;
        while(true)
            if(*p=='*')
                rs=s, rp=++p;
            else if(!*s)
                return !*p;
            else if(*s==*p || *p=='?')
                ++s, ++p;
            else if(rs)
                s=++rs, p=rp;
            else
                return false;
    }
    inline bool match_pattern(const std::wstring& value, const wchar_t* mask)
        { return match_pattern(value.c_str(), mask); }
 
    inline bool match_pattern(const wchar_t* value, const std::wstring& mask)
        { return match_pattern(value, mask.c_str()); }
 
    inline bool match_pattern(const std::wstring& value, const std::wstring& mask)
        { return match_pattern(value.c_str(), mask.c_str()); }
теперь сложность ушла.
и код настолько простой,
что в нем без труда сможет разобраться даже новичок.
самое главное - ушла зависимость от чего то сложного и непонятного.

этот код легко можно отсадить в какой нибудь другой проект.
он уже не тянет за самой кучу всякой непонятной шаблоно-ботвы.

но за это пришлось заплатить копипастой.


вопрос к сообществу:
как вы считаете, что лучше?


представьте себе, что нужно иметь дело не с 1 функцией,
а с апи... функций на 50.

копипасту начнет зашкаливать.
или начнет зашкаливать сложность шаблонов.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
18.10.2017, 19:25
Ответы с готовыми решениями:

Как вычислять сложность алгоритма, или найти асимптотическую сложность любой программки?
Например Вычислить x^n по алгоритму быстрого возведения в степень Добавлено через 43 секунды...

Дизайн сайтов (desktop и адаптивный дизайн), баннеров и логотипов
Добрый день! Меня зовут Катя. Я - начинающий дизайнер. Рисую за гроши сайты (desktop и адаптивный...

Дизайн выпадающего меню под дизайн обычного
Здравствуйте, у меня то есть меню, но, есть одно но... Есть меню в стиле лава-лампы, и я хочу...

С++ идиомы - обсуждение
Тема создана для вопросов и обсуждений С++ идиом

__________________

Записывайтесь на профессиональные курсы C++ разработчиков
10
Форумчанин
Эксперт CЭксперт С++
8165 / 5013 / 1436
Регистрация: 29.11.2010
Сообщений: 13,455
19.10.2017, 11:43 2
Почему бы не оставить единственный вариант?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef UNICODE
    using tstring = std::string;
#else
    using tstring = std::wstring;
#endif
 
bool match_pattern(const tstring& value, const tstring& mask)
{
    using ch = tstring::const_pointer;
    ch s = &value[0];
    ch p = &mask[0];
 
    ch rs=0, rp=0;
    while(true)
        if(*p=='*')
            rs=s, rp=++p;
        else if(!*s)
            return !*p;
        else if(*s==*p || *p=='?')
            ++s, ++p;
        else if(rs)
            s=++rs, p=rp;
        else
            return false;
}
Либо (если нужно поддержать и юникодный вариант и обычный)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template <typename CharT>
bool match_pattern(const std::basic_string<CharT>& value, const std::basic_string<CharT>& mask)
{
    const CharT *s = &value[0];
    const CharT *p = &mask[0];
 
    const CharT *rs=0, *rp=0;
    while(true)
        if(*p=='*')
            rs=s, rp=++p;
        else if(!*s)
            return !*p;
        else if(*s==*p || *p=='?')
            ++s, ++p;
        else if(rs)
            s=++rs, p=rp;
        else
            return false;
}
Что бы ни было - DRY. Изменять один и тот же код в нескольких местах при любом изменении алгоритма - не комильфо.
0
Эксперт С++
8421 / 3954 / 866
Регистрация: 15.11.2014
Сообщений: 8,904
19.10.2017, 15:25  [ТС] 3
Цитата Сообщение от MrGluck Посмотреть сообщение
Почему бы не оставить единственный вариант?
потому, что если бы это было приемлемо,
этой темы бы не существовало.


Цитата Сообщение от MrGluck Посмотреть сообщение
const std::basic_string<CharT>& value
1.
смысл менять один шаблон на другой?

2.
теперь код не эффективен.
будет зажирать на стрингах
без необходимости.

3.
нельзя подсунуть какие то другие строки.
0
Форумчанин
Эксперт CЭксперт С++
8165 / 5013 / 1436
Регистрация: 29.11.2010
Сообщений: 13,455
19.10.2017, 17:40 4
Цитата Сообщение от hoggy Посмотреть сообщение
теперь код не эффективен.
будет зажирать на стрингах
без необходимости.
Так у тебя же выше
Цитата Сообщение от hoggy Посмотреть сообщение
C++
1
2
std::string ss(value);
std::string pp(mask );
1
Эксперт С++
8421 / 3954 / 866
Регистрация: 15.11.2014
Сообщений: 8,904
19.10.2017, 18:57  [ТС] 5
Цитата Сообщение от MrGluck Посмотреть сообщение
Так у тебя же выше
кстати да.
мерси.
Цитата Сообщение от Atakai Посмотреть сообщение
Хорошая виндовая практика
это - виндузятно-сишное наследие.
от которого многие уже давно отказываются.

особенно, круто выходит костылями,
если нужна кроссплатформа.

шаблон позволяет вообще не заморачиваться:
char или wchar_t
0
Форумчанин
Эксперт CЭксперт С++
8165 / 5013 / 1436
Регистрация: 29.11.2010
Сообщений: 13,455
20.10.2017, 12:14 6
hoggy, что бы ни было - я считаю копипасту хуже сложности. Если код "сложен" - его можно прокомментировать/задокументировать.
В случае, если нужно предусмотреть вариант для char и wchar_t - я бы предпочёл обернуть всё это в шаблон.
Цитата Сообщение от hoggy Посмотреть сообщение
смысл менять один шаблон на другой?
Под class s1 может подойти что угодно. А в случае std::basic_string<CharT>, мы явно подчёркиваем, что используем строки, при этом у нас может быть разный тип. Это, возможно, дело вкуса.
Про другие строки в задании не говорилось.

Касаемо перегруженных вариантов с basic_string, вызывающих c_str() - не вижу ничего плохого. Если такая оптимизация востребована, пусть будет (про SSO ты наверняка знаешь). В конце-концов, код этих функций меняться не будет. В отличие от версии, где задан алгоритм.

Вобщем на единственный вопрос (что выбрать) я ответ высказал.
2
Эксперт С++
8421 / 3954 / 866
Регистрация: 15.11.2014
Сообщений: 8,904
20.10.2017, 14:27  [ТС] 7
Цитата Сообщение от MrGluck Посмотреть сообщение
Под class s1 может подойти что угодно. А в случае std::basic_string<CharT>, мы явно подчёркиваем, что используем строки, при этом у нас может быть разный тип. Это, возможно, дело вкуса.
Про другие строки в задании не говорилось.
говорилось:

Цитата Сообщение от hoggy Посмотреть сообщение
компилятор будет генерировать эффективный код
для любых входных аргументов.
код из первого примера без каких либо модификаций скушает и QString,
и сишную строку, и стдешную, и вообще любые стринги.
если уж решили юзать шаблон - зачем ограничиваться std ?

Цитата Сообщение от MrGluck Посмотреть сообщение
не вижу ничего плохого.
на 1 единственной функции в итоге расплодилась куча перегрузок.
а если там апи из 100 функций?

я пока их писал уже тогда понял - лучше оставить 1 шаблон.
в итоге, как мне кажется получается,
и лаконичнее,
и проще.

и если позарез нужно будет избавиться от зависимостей от хедеров,
шаблон легко скопипастить и переделать под ключ.
0
1378 / 405 / 144
Регистрация: 22.10.2014
Сообщений: 872
21.10.2017, 10:48 8
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template<typename T, typename M>
bool match_pattern(const T& value, const M& mask) {
    auto s = std::begin(value);
    auto p = std::begin(mask);
 
    const auto se = std::end(value);
    const auto pe = std::end(mask);
 
    auto rs = se;
    auto rp = pe;
    while (true)
        if (*p == '*')
            rs = s, rp = ++p;
        else if (s == se)
            return p != pe;
        else if (*s == *p || *p == '?')
            ++s, ++p;
        else if (rs != se)
            s = ++rs, p = rp;
        else
            return false;
}
Нужно проверить логику, ибо я не разбирался, а "ручной автозаменой" жахнул.
0
Любитель чаепитий
3543 / 1653 / 508
Регистрация: 24.08.2014
Сообщений: 5,614
Записей в блоге: 1
21.10.2017, 18:19 9
Цитата Сообщение от Nosey Посмотреть сообщение
Нужно проверить логику
не работает так:
C++
1
2
3
const char * s = "ololo";
//...
match_pattern(s, "olo*");
2
1378 / 405 / 144
Регистрация: 22.10.2014
Сообщений: 872
21.10.2017, 21:11 10

Не по теме:

GbaLog-, Эээ, дорогой, этож не логика - раз. И мы же вроде в ветке С++ - два (что за си строки) :)


Ну и да, конечно так не будет работать.
Т.е. меня мой вариант устроил бы. Если раз в тыщу лет мне потребуется с си строками поработать, то можно накатать специализацию std::begin&end<const char*> через strlen, wchar туда же. Ну либо сконструировать std::string.
0
Эксперт С++
8421 / 3954 / 866
Регистрация: 15.11.2014
Сообщений: 8,904
22.10.2017, 18:07  [ТС] 11
Цитата Сообщение от Nosey Посмотреть сообщение
Нужно проверить логику, ибо я не разбирался, а "ручной автозаменой" жахнул.
значит вы - за шаблон.

Цитата Сообщение от Nosey Посмотреть сообщение
меня мой вариант устроил бы
моральный шаблон, ориентированный на работу со строками,
должен уметь работать с различными типами строк.

а то ведь с таким успехом можно сделать обычную функцию,
для std::string, и сказать:
"а чо? меня устраивает. нужно std::wstring, можно накатать рядышком"

Цитата Сообщение от Nosey Посмотреть сообщение
можно накатать специализацию std::begin&end<const char*> через strlen, wchar туда же
ну вот примерно так и родился
Цитата Сообщение от hoggy Посмотреть сообщение
#include <tools/text.h>
сейчас он содержит весь необходимый стафф
для быстрого запиливания универсальных шаблонов.

вот только код в итоге получается шаблонным по все поля.
и тянет за собой все эти вспомогательные деталюшки-зависимости.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
22.10.2017, 18:07

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Обсуждение COBOL
Всем привет. Мало кто знает COBOL на сегодняшний день... По иронии судьбы я работаю именно с ним...

Обсуждение по книге
Как происходит выбор песни по переменной tittle Где мы используем переменную artist Не пойму...

Обсуждение литературы
Давайте-ка поделимся и обсудим плюсы и минусы книг программирование андроид устройств. Итак я...

Обсуждение литературы
День добрый! Сам авопрос: В документе Общая концепция.doc - есть пункт по созданию Фреймсетов,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.