Re[3]: Код: версия 0.00000003 - бенчмарки
От: Зверёк Харьковский  
Дата: 25.11.03 19:20
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>...запустил нижеприведенную програмку и просто офигел...

TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько
TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>


хм... внушаить.
FAQ — це мiй ай-кью!
Re[3]: Код: версия 0.00000003 - бенчмарки
От: WolfHound  
Дата: 26.11.03 05:28
Оценка: +1
Здравствуйте, TepMuHyc, Вы писали:

TMH>...запустил нижеприведенную програмку и просто офигел...

TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько
TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>


А не пойти ли тебе в boost с такими то результатами?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Код: версия 0.00000003 - бенчмарки
От: WFrag США  
Дата: 27.11.03 02:00
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>...запустил нижеприведенную програмку и просто офигел...

TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько
TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>



Попробуй со spirit-ом сравнить, интересно на результат посмотретью...
Re[3]: Код: версия 0.00000003 - бенчмарки
От: e-Xecutor Россия  
Дата: 08.12.03 09:14
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>
TMH># matches: 60000 # fails: 40000
TMH>my time: 40

TMH># matches: 60000 # fails: 40000
TMH>boost time: 3055
TMH>


Эххх. Не догнал я тебя

# matches: 60000 # fails: 40000
my time: 29
# matches: 60000 # fails: 40000
boost time: 2462
# matches: 60000 # fails: 40000
skv time: 89


Что впрочем предсказуемо.
Но, учитывая, что мой код не inline, а статическая либа,
думаю что неплохо
Если компилировать не с /O2 а /O1, то одинаковое время
Но всё равно впечатляет, возьму на заметку
Re[4]: Код: версия 0.00000003 - бенчмарки
От: Аноним  
Дата: 09.12.03 23:49
Оценка:
Здравствуйте, e-Xecutor, Вы писали:
(отвечает TepMuHyc которого задолбал РСДН)

EX>
EX># matches: 60000 # fails: 40000
EX>my time: 29
EX># matches: 60000 # fails: 40000
EX>boost time: 2462
EX># matches: 60000 # fails: 40000
EX>skv time: 89
EX>


Что есть "skv" и с чем его можно покушать? Иными словами код в студию...
...А то я к аутпуту могу что хошь приписать... даже отрицательные числа...
Re[6]: Код: версия 0.00000001
От: Злость Россия  
Дата: 10.12.03 08:00
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

TMH>Здравствуйте, Кодт, Вы писали:


К>>Где-нибудь наверху определи константу -- enum или просто #define. Чтобы потом можно было по-быстрому править...

TMH>...это и ежу понятно — писать 0xBAADC0DE 28 раз — можно и мозоли на пальчиках заработать — проще
TMH>enum{ stopch = 0xBAADC0DE };

А я наверное заменю на 0xdeadbeef
Правда, Ложь — мне все одно — я имею свое мнение.
Если функция недокументированна — это не значит, что ее не используют все ваши конкуренты в своих продуктах.
Любой строй переходный и отрицать это значит быть закостенелым идиотом.
Re[5]: Код: версия 0.00000003 - бенчмарки
От: e-Xecutor Россия  
Дата: 10.12.03 08:21
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, e-Xecutor, Вы писали:

А>(отвечает TepMuHyc которого задолбал РСДН)

EX>>
EX>># matches: 60000 # fails: 40000
EX>>my time: 29
EX>># matches: 60000 # fails: 40000
EX>>boost time: 2462
EX>># matches: 60000 # fails: 40000
EX>>skv time: 89
EX>>


А>Что есть "skv" и с чем его можно покушать? Иными словами код в студию...

А>...А то я к аутпуту могу что хошь приписать... даже отрицательные числа...
skv — это моя библиотечка regexp-ов.
точнее это мои инициалы
Кода там больше ста кил, так что студия треснет, если его в неё внести
Всё не соберусь доку написать да выложить куда-нить...
Re[3]: Код: версия 0.00000003 - бенчмарки
От: Tonal- Россия www.promsoft.ru
Дата: 25.12.03 22:12
Оценка:
Здравствуйте, TepMuHyc, Вы писали:

У меня не совирается на mingw32 v 3.2.3
пишет

bench.cpp: In function `bool is_ftpanswer(const std::string&)':
bench.cpp:37: no matching function for call to `
   static_regex::seq<static_regex::select<static_regex::plus<static_regex::digit>
   >, static_regex::select<static_regex::alt<static_regex::cc<45, 32, 
   -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, 
   -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, -045523f22, 
...



Да, это после того, как я в строках 14-16 явно квалифицировал select, а то g++ его с select-ом из winsock путал.
Re[4]: Код: версия 0.00000003 - бенчмарки
От: Tonal- Россия www.promsoft.ru
Дата: 27.12.03 16:58
Оценка:
T>У меня не собирается на mingw32 v 3.2.3
Решил проблему.

Всё дело было в функции is_ftpanswer
bool is_ftpanswer(const string& data)
{
    int nsubm;
    string::const_iterator subm[2*10];

    if( rx_ftp::match(data.begin(), data.end(), subm, nsubm=0) )
    {
        return true;
    }
    return false;
}


Объявление match выглядит так
template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)

и mingw естественно отказывался привязать временную переменную полученную из data.begin() к it.

Введение локальной переменной решило проблему.

Функция получилась такая:
bool is_ftpanswer(const string& data) {
  int nsubm = 0;
  string::const_iterator subm[2*10];
  string::const_iterator start = data.begin();
  return rx_ftp::match(start, data.end(), subm, nsubm);
}


Не совсем понятно как VC пропустил такую глюку.

Да, время окончания цикла наверное лучше мерить по окончанию цикла, а не в коде вывода отчёта.
... << RSDN@Home 1.1.0 stable >>
Re[3]: Код: версия 0.00000003 - бенчмарки
От: Tonal- Россия www.promsoft.ru
Дата: 27.12.03 18:13
Оценка:
TMH>Я, конечно ожидал, что инлайновый код быстрый, но чтобы настолько

Присоединяюсь!
Вот мои данные
Машина : P3 666Mz 256Mb WinXP
Компилер : g++ (GCC) 3.2.3 (mingw special 20030504-1)

Я немного переделал код — привожу ниже.

C:\Lang\Projects\test\static_regex>g++ -obench bench.cpp -lboost_regex
C:\Lang\Projects\test\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 1231
# matches: 60000 # fails: 40000
boost time: 13179

C:\Lang\Projects\test\static_regex>g++ -O2 -mcpu=pentiumpro -obench bench.cpp -lboost_regex
C:\Lang\Projects\test\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 120
# matches: 60000 # fails: 40000
boost time: 4757


Если использовать is_ftpanswer2 вместо is_ftpanswer
C:\static_regex>g++ -obench bench.cpp -lboost_regex
C:\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 1011
# matches: 60000 # fails: 40000
boost time: 13079

C:\static_regex>g++ -O2 -mcpu=pentiumpro -obench bench.cpp -lboost_regex
C:\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 80
# matches: 60000 # fails: 40000
boost time: 4617



#include <windows.h>
#include <string>
#include <iostream>
#include "static_regex.h"

#define BOOST_REGEX_STATIC_LINK
#include <boost/regex.hpp>

using std::string;
namespace
{
  using namespace static_regex;
  typedef
  seq<
    static_regex::select< plus<digit> >,               //код ответа
    static_regex::select< alt<cc<'-',' '>, endl> >,    //символ переноса - если '-' - то ответ многострочный
    static_regex::select< star<not_cc<'\r','\n'> > >,  //текст сообщения - все до конца строки
    opt<endl>                            //необязательный перевод строки
  >
  rx_ftp;

  boost::regex brx_ftp("([0-9]+)([\\- ]|(?:\r?\n))([^\r\n]*)(?:\r?\n)?");
}

string data[] = {
  "202Slightly malformed response\r\n",
  "200 Hello beutiful world\n",
  "201-Hello nice and beutiful world\n",
  "202-Hello sometimes nice and beutiful but mostly ugly world\r\n",
  "Not a response at all\r\n",
};

bool is_ftpanswer(const string& data) {
  int nsubm = 0;
  string::const_iterator subm[2*10];
  string::const_iterator start = data.begin();
  return rx_ftp::match(start, data.end(), subm, nsubm);
}

bool is_ftpanswer2(const string& data) {
  string::const_iterator start = data.begin();
  return rx_ftp::match(start, data.end());
}

bool bis_ftpanswer(const string& data) {
  boost::smatch what;
  return boost::regex_match(data, what, brx_ftp);
}

int main() {
  const int NITER = 20000;

  int nmatches = 0, nfails = 0;
  DWORD start = GetTickCount();
  for (int i=0; i < NITER; i++) {
    for (int r=0; r<5; r++)
      is_ftpanswer(data[r])
        ? ++nmatches : ++nfails;
  }
  DWORD stop = GetTickCount();
  std::cout << "# matches: " << nmatches << " # fails: " << nfails << std::endl;
  std::cout << "my time: " << (stop - start) << std::endl;

  nmatches = nfails = 0;
  start = GetTickCount();
  for (int i=0; i < NITER; i++) {
    for (int r=0; r<5; r++)
      bis_ftpanswer( data[r] )
        ? ++nmatches : ++nfails;
  }
  stop = GetTickCount();
  std::cout << "# matches: " << nmatches << " # fails: " << nfails << std::endl;
  std::cout << "boost time: " << (stop - start) << std::endl;
}
... << RSDN@Home 1.1.0 stable >>
Re[2]: Код: версия 0.00000003
От: Tonal- Россия www.promsoft.ru
Дата: 27.12.03 19:50
Оценка:
Напрашиваются ещё 2 полезные фичи:
"." — любой символ
"$" — конец последовательности

struct dot {/*any character*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      bool res = (it != end);
      if( res ) ++it;
      return res;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it,end);
  }
};

struct ends {/*end of input sequence*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return it == end;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it, end);
  }
};
... << RSDN@Home 1.1.0 stable >>
Re[2]: Код: версия 0.00000003
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 11:32
Оценка:
Обнаружил интересную фигню в работе с групировками:


Вот такое выражение:
Perl
/([abc])*/

static_regex
typedef star< select< cc<'a', 'b', 'c'> > > rx_star_sel_test;


Как вы думаете, сколько (максимум) груп оно найдёт в строке?
Ответ такой: всё зависит от строки.
в сторке "abc" 3 группы, в сторке "aaabbbccc" — 9.

Теперь немного изменим выражение:
Perl
/(?:([abc])|([def]))*/

static_regex
typedef star<
  alt< 
        select< cc<'a', 'b', 'c'> >,
        select< cc<'d', 'e', 'f'> >,
    >
> rx_star_sel_test;


И попытаемся ответить на вопрос как отделить группы найденные первой альтернативой от групп второй?
Ответ — никак.

Чтобы решить эту проблему, предлагаю придерживаться следуюших правил:
1) Количество найденных групп = количеству select-ов в выражении.
2) Несовпавшая группа обнуляется.
3) star и plus запоминают последнюю найденную группу.
4) для star — пустое совпадение — оба итератора указывают на место этого совпадения.

При этом можно на этапе компиляции подсчитать размер массива, нужного для хранения групп.
А так же несколько оптимизировать вычисления (если известно что групп нет — вызываем версию не работаюшую с группами).

Ниже приводиться исходник, где всё это реализованно.
//http://www.rsdn.ru/Forum/Message.aspx?mid=456007&only=1
//0.00000003
#ifndef __STATIC_REGEX_H_INCLUDED__
#define    __STATIC_REGEX_H_INCLUDED__
namespace static_regex {

typedef wchar_t rx_char;
struct seqe {};
enum { stpc = 0xBAADC0DE };
template<bool> struct grp_present {};

template<rx_char E>
struct c {/* literal charachter */
    static bool char_match(rx_char ch)
        { return (E == ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (E == static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct s {/* literal string - up to 30 symbols */
    typedef s<
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    enum { length = 1 + tail::length };
    template<class InIt>
    static bool do_match(InIt& it)
    {
        return (c0 == static_cast<rx_char>(*it)) && tail::do_match(++it);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt tend( it + length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        bool res = do_match(it);
        if( !res ) it = t;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};
template<> struct s<
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    enum { length = 0 };

    template<class InIt>
    static bool do_match(InIt&)
        { return true; }
};

template<
    bool INCLUSIVE,
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc_ /* charachter class - like "[abcdEF]" or "[^abcdEF]" */
{
    typedef cc_<INCLUSIVE,
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    static bool char_match(rx_char ch)
        { return (c0 == ch) || tail::char_match(ch); }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<> struct cc_<true,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<> struct cc_<false,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc:cc_<true,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct not_cc:cc_<false,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<rx_char F, rx_char B, bool INCLUSIVE=true>
struct range /* charachter range - like "[a-d]" or "[^a-d]" */
{
    static bool char_match(rx_char ch)
    {
        return (((F < B) ? F : B) <= ch) && (ch <= ((F < B) ? B : F));
    }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<
    class CC0,      class CC1,      class CC2=seqe, class CC3=seqe, class CC4=seqe,
    class CC5=seqe, class CC6=seqe, class CC7=seqe, class CC8=seqe, class CC9=seqe>
struct set {/* charachter set */
    typedef set<CC1,CC2,CC3,CC4,CC5,CC6,CC7,CC8,CC9,seqe> tail;

    static bool char_match(rx_char ch)
    {
        return CC0::char_match(ch) || tail::char_match(ch);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match( static_cast<rx_char>(*it) );
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
};

template<> struct set<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    static bool char_match(rx_char)
        { return false; }
};

template<class RX>
struct star {/* zero or more occurences of RX - like "(abc)*" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        while( RX::match(it,end) );
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
      return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      InIt _sel2[2*RX::sel_len];
      int _nsel = 0, _nsel2 = 0;
      while (RX::match(it, end, _sel2, _nsel)) {
        for (int i = 0; i < 2*_nsel; ++i)
          sel[i] = _sel2[i];
        _nsel2 = _nsel;
        _nsel = 0;
      }
      if (_nsel2)
        nsel += _nsel2;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it,end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
};

template<class RX>
struct plus {/* one or more occurences of RX - like "(abc)+" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end) && star<RX>::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
        return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      int _nsel2 = 0;
      InIt _sel2[2*RX::sel_len];
      if (!RX::match(it, end, _sel2, _nsel2))
        return false;

      int _nsel = 0;
      star<RX>::match(it, end, sel, _nsel);
      if (!_nsel) {
        for (int i = 0; i < _nsel2; ++i)
          sel[i] = _sel2[i];
        _nsel = _nsel2;
      }
      nsel += _nsel;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it, end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
};

template<class RX>
struct opt {/* optional occurence of RX - like "(abc)?" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        RX::match(it, end);
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        RX::match(it, end, sel, nsel);
        return true;
    }

    enum {sel_len = RX::sel_len};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct seq /* sequence of RX - like "(abc)(def)" */
{
    typedef seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end)
    {
        return RX0::match(it,end) && tail::do_match(it,end);
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        return RX0::match(it, end, sel, nsel)
            && tail::do_match(it, end, sel + RX0::sel_len, nsel);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt itbk(it);
        bool res = do_match(it, end);
        if (!res)
          it = itbk;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        InIt itbk(it);
        int nselbk = nsel;
        bool res = do_match(it, end, sel, nsel);
        if( !res ) {
            it = itbk;
            nsel = nselbk;
        }
        return res;
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
};

template<> struct seq<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end)
        { return true; }
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
        { return true; }

    enum {sel_len = 0};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct alt /* alternative - like "(abc|def)" */
{
    typedef alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        if (RX0::match(it, end))
          return true;
        else
          return tail::match(it, end);
    }

    template<class InIt>
      static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
        if (RX0::match(it, end, sel, nsel))
          return true;
        else
          return tail::match(it, end, sel + RX0::sel_len, nsel);
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
};

template<> struct alt<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
        { return false; }
    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
        { return false; }

    enum {sel_len = 0};
};

template<class RX>
struct select
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      InIt first(it);
      int _nsel = 0;
      if (RX::match(it, end, sel + 2, _nsel)) {
        sel[0] = first;
        sel[1] = it;
        nsel += 1 + _nsel;
        return true;
      } else {
        sel[0] = sel[1] = InIt();
        return false;
      }
    }

    enum {sel_len = 1};
};

//-////////////////////////////////////////////////////////////////////////
template<bool INCLUSIVE> struct ws_
    :cc<INCLUSIVE, ' ', '\t'>
    {};
typedef ws_<true> ws;
typedef ws_<false> not_ws;

template<bool INCLUSIVE> struct digit_
    :range<'0','9',INCLUSIVE>
    {};
typedef digit_<true> digit;
typedef digit_<false> not_digit;

template<bool INCLUSIVE> struct xdigit_
    :set< range<'0','9',INCLUSIVE>, range<'A','F',INCLUSIVE>, range<'a','f',INCLUSIVE> >
    {};
typedef digit_<true> xdigit;
typedef digit_<false> not_xdigit;

template<bool INCLUSIVE> struct alpha_
    :set< range<'A','Z',INCLUSIVE>, range<'a','z',INCLUSIVE> >
    {};
typedef alpha_<true> alpha;
typedef alpha_<false> not_alpha;

template<bool INCLUSIVE> struct alphanum_
    :set< alpha_<INCLUSIVE>, digit_<INCLUSIVE> >
    {};
typedef alphanum_<true> alphanum;
typedef alphanum_<false> not_alphanum;

struct endl:seq< opt< c<'\r'> >, c<'\n'> > {};

//Shura added
struct dot {/*any character*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      bool res = (it != end);
      if( res ) ++it;
      return res;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it,end);
  }

  enum {sel_len = 0};
};//dot /*any character*/

struct ends {/*end of input sequence*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return it == end;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it, end);
  }

  enum {sel_len = 0};
};//ends /*end of input sequence*/

}//namespace static_regex
#endif//__STATIC_REGEX_H_INCLUDED__
... << RSDN@Home 1.1.0 stable >>
Предложения по дальнейшей разработке
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 12:11
Оценка:
Предложения по дальнейшей разработке:

1) Может всёж-таки завести структурку для группировки — ато некошерно как-то получается...
К тому же требующийся размер массива можно теперь вычислить.

2) Выражение типа
Perl
/.*\.cpp/

static_regex
typedef seq< star<dot>, c<'.'>, s<'c', 'p', 'p'> > rx_cpp_file;

Не могут быть найдены — т.к. операторы повторения (star, plus, opt) реализованы как "неуступчивые". Т.е. заняв какой-либо символ, они не умеют отдать его назад.
К сожалению проблема не в коде этих операторов, а во взаимодействии их и последующих.
Т.е. эту проблему, предположительно, можно решить подправив код seq::match.

3) Завести перегруженные функции помощники, типа:
//Приверка последовательности
template <class RX, class Iter>
bool test(RX, Iter first, Iter last);

//Приверка последовательности и заполнение групп
template <class RX, class Iter>
bool match(RX, Iter first, Iter last, RX::groups&);

//Поиск в последовательности
template <class RX, class Iter>
bool search(RX, Iter first, Iter last, RX::groups&);

Можно ещё для string перегрузить...
... << RSDN@Home 1.1.0 stable >>
Re: Предложения по дальнейшей разработке
От: Аноним  
Дата: 29.12.03 13:12
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Предложения по дальнейшей разработке:


T>1) Может всёж-таки завести структурку для группировки — ато некошерно как-то получается...

Пришел к аналогичному выводу. Скоро выложу.

T>2) Выражение типа "/.*\.cpp/" Не могут быть найдены.

Известная беда всех реализаций регулярных выражений.
Что же касается "нежадных" операторов, то у регулярного выражения есть задача: "найти наидлиннейшее совпадение". Чтобы решить ее с "нежадными" операторами, придется перепробовать все комбинаци их "жадности" — от "совсем нежадный" до "почти жадный". Задачка не для слабонервных. И сложность у нее полиномиальная, а то и (не приведи господь) экспоненциальная.

Так что увольте, "нежадные" операторы не будут реализованы никогда — проще потребовать от программиста
чтобы он писал выражения учитывающие "жадность".

например так:
/.*\.cpp/ <==> /[^.]*\.cpp/


T>3) Завести перегруженные функции помощники, типа:

Никто не мешает. Но это лучше отдать на откуп "прикладному программисту"

T>//Поиск в последовательности

T>template <class RX, class Iter>
T>bool search(RX, Iter first, Iter last, RX::groups&);
T>[/ccode]
Это еще одна задача из разряда "и хочется и колется"..
"brute force" подход всегда открыт, но мне не нравится его сложность: O(length(rx) * length(string))
Думаю как притянуть сюда алгоритм Кнута-Морриса-Пратта, но в данной реализации это скорее всего нереализуемо (точнее, реализуемо, но компилируется ОЧЕНЬ долго)


T>Можно ещё для string перегрузить...

Опять-таки "прикладной программист" напишет этот костыль для себя гораздо лучше чем я для него.
Re[2]: Предложения по дальнейшей разработке
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 19:13
Оценка:
Ура, я тут не один! ;-в

T>>2) Выражение типа "/.*\.cpp/" Не могут быть найдены.

А>Известная беда всех реализаций регулярных выражений.
А>Что же касается "нежадных" операторов, то у регулярного выражения есть задача: "найти наидлиннейшее совпадение". Чтобы решить ее с "нежадными" операторами, придется перепробовать все комбинаци их "жадности" — от "совсем нежадный" до "почти жадный". Задачка не для слабонервных. И сложность у нее полиномиальная, а то и (не приведи господь) экспоненциальная.
Мне кажется, ты немножко путаешь понятия:
Квалификатор повторения может быть "жадным" и "не жадным".
"Жадные" могут быть "уступчивым" и "неуступчивым".
Так что имеем 3 варианта.
Сейчас у нас "жадный неуступчивый", т.е. система не поддерживает откатов.
Это не даёт написать выражение типа "оканчивается на" в обшем виде. Например нельзя написать выражение для выделения доменов первого уровня в url-е, или для выделения имени файла (ведь "." — допустимый символ). Для обработки подобных выражений придётся прибегать к другой библиотеке, а не хочется.
А насчёт "наидлиннейшего" совпадения — для отыскания оного, надо перебрать все возможные варианты.
Пример
"abcc"
/(a*)(abc+|b)/

Тут "наидлиннейшее" бидет вся сторка по пустой первой группе и первой алтернативе во второй. Её и найдёт ДКА, или POSIX НКА. Ну а обычный НКА или интерпретатор найдёт только "ab".

Так что я предлагаю не очень напрягаться по этому поводу (Perl ведь не напрягаются). Лучше попытаться построить ДКА.

А на счёт нетривиальности задачки — всё это достаточно просто реализовать (код ниже).
Чтобы не слишком тормазило решения такие:
А) Для всех классов определить константу undoable — откатываемость.
А1) Для терминалов (c, cc, s...) — false.
А2) Для повторителей и альтернативы — true.
А3) Для контейнеров — вычисляется по или от содержимого.
Б) В последовательности разбираем разные варианты и пишем код.
В) Создаём класс контейнер noundo — который делает содержащееся в нём выражение неуступчивым (undoable = false).

Для моего бенчмарка эта версия даёт всего лишь 4-5 кратный выигрышь в скорости по сравнению с boost::regex.
Но, если переписать варажение с использованием noundo в разумнвх местах, то опять выигрыш примерно на 1,5-2 порядка!

Выражение вот:
  typedef seq<
    noundo< select< plus<digit> > >,               //код ответа
    noundo< select< alt<cc<'-',' '>, endl> > >,    //символ переноса - если '-' - то ответ многострочный
    select< star<not_cc<'\r','\n'> > >,            //текст сообщения - все до конца строки
    opt<endl>                            //необязательный перевод строки
  >
  rx_ftp2;

Вот результат:
C:\static_regex>g++ -O2 -mcpu=pentiumpro -pipe -obench bench.cpp -lboost_regex
C:\static_regex>bench.exe
# matches: 60000 # fails: 40000
my time: 1802
# matches: 60000 # fails: 40000
my noundo time: 140
# matches: 60000 # fails: 40000
boost time: 4647


T>>3) Завести перегруженные функции помощники, типа:

А>Никто не мешает. Но это лучше отдать на откуп "прикладному программисту"
Я всёж таки изобразил 2 перегруженных варианта test. Зачем плодить везде одинаковые куски, если можно их вставить в библиотеку не нарушая единства.
Остальные — подожду структурку для групп. ;-в

T>>//Поиск в последовательности
T>>template <class RX, class Iter>
T>>bool search(RX, Iter first, Iter last, RX::groups&);
T>>

А>Это еще одна задача из разряда "и хочется и колется"..
А>"brute force" подход всегда открыт, но мне не нравится его сложность: O(length(rx) * length(string))
А>Думаю как притянуть сюда алгоритм Кнута-Морриса-Пратта, но в данной реализации это скорее всего нереализуемо (точнее, реализуемо, но компилируется ОЧЕНЬ долго)
Тут тоже есть много вариантов для оптимизации... хотя согласен, надо пока обдумать...

Таки код:
//http://www.rsdn.ru/Forum/Message.aspx?mid=456007&only=1
//0.00000003
#ifndef __STATIC_REGEX_H_INCLUDED__
#define    __STATIC_REGEX_H_INCLUDED__
namespace static_regex {

typedef wchar_t rx_char;
struct seqe {};
enum { stpc = 0xBAADC0DE };
template<bool> struct grp_present {};

template<rx_char E>
struct c {/* literal charachter */
    static bool char_match(rx_char ch)
        { return (E == ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) && (E == static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct s {/* literal string - up to 30 symbols */
    typedef s<
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    enum { length = 1 + tail::length };
    template<class InIt>
    static bool do_match(InIt& it)
    {
        return (c0 == static_cast<rx_char>(*it)) && tail::do_match(++it);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        InIt tend( it + length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        bool res = do_match(it);
        if( !res ) it = t;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};
template<> struct s<
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    enum { length = 0 };

    template<class InIt>
    static bool do_match(InIt&)
        { return true; }
};

template<
    bool INCLUSIVE,
    int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
    int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
    int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc_ /* charachter class - like "[abcdEF]" or "[^abcdEF]" */
{
    typedef cc_<INCLUSIVE,
        c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
        c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
        c21,c22,c23,c24,c25,c26,c27,c28,c29,stpc
    > tail;

    static bool char_match(rx_char ch)
        { return (c0 == ch) || tail::char_match(ch); }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<> struct cc_<true,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<> struct cc_<false,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc,
    stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc, stpc>
{
    static bool char_match(rx_char ch)
        { return false; }
};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct cc:cc_<true,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<
int c0,       int c1,       int c2 =stpc, int c3 =stpc, int c4 =stpc, int c5 =stpc, int c6 =stpc, int c7 =stpc, int c8 =stpc, int c9 =stpc,
int c10=stpc, int c11=stpc, int c12=stpc, int c13=stpc, int c14=stpc, int c15=stpc, int c16=stpc, int c17=stpc, int c18=stpc, int c19=stpc,
int c20=stpc, int c21=stpc, int c22=stpc, int c23=stpc, int c24=stpc, int c25=stpc, int c26=stpc, int c27=stpc, int c28=stpc, int c29=stpc>
struct not_cc:cc_<false,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29>
    {};

template<rx_char F, rx_char B, bool INCLUSIVE=true>
struct range /* charachter range - like "[a-d]" or "[^a-d]" */
{
    static bool char_match(rx_char ch)
    {
        return (((F < B) ? F : B) <= ch) && (ch <= ((F < B) ? B : F));
    }

    template<bool> struct sel {};
    static bool char_match(rx_char ch, sel<true>)
        { return char_match(ch); }
    static bool char_match(rx_char ch, sel<false>)
        { return !char_match(ch); }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match(static_cast<rx_char>(*it), sel<INCLUSIVE>());
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<
    class CC0,      class CC1,      class CC2=seqe, class CC3=seqe, class CC4=seqe,
    class CC5=seqe, class CC6=seqe, class CC7=seqe, class CC8=seqe, class CC9=seqe>
struct set {/* charachter set */
    typedef set<CC1,CC2,CC3,CC4,CC5,CC6,CC7,CC8,CC9,seqe> tail;

    static bool char_match(rx_char ch)
    {
        return CC0::char_match(ch) || tail::char_match(ch);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        bool res = (it != end) &&
            char_match( static_cast<rx_char>(*it) );
        if( res ) ++it;
        return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
    {
        return match(it,end);
    }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<> struct set<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    static bool char_match(rx_char)
        { return false; }
};

template<class RX>
struct star {/* zero or more occurences of RX - like "(abc)*" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        while( RX::match(it,end) );
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
      return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      InIt _sel2[2*RX::sel_len];
      int _nsel = 0, _nsel2 = 0;
      while (RX::match(it, end, _sel2, _nsel)) {
        for (int i = 0; i < 2*_nsel; ++i)
          sel[i] = _sel2[i];
        _nsel2 = _nsel;
        _nsel = 0;
      }
      if (_nsel2)
        nsel += _nsel2;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it, end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
    enum {undoable = 1};
};

template<class RX>
struct plus {/* one or more occurences of RX - like "(abc)+" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end) && star<RX>::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&, grp_present<false>) {
        return match(it, end);
    }

    template<class InIt>
    static bool match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      int _nsel2 = 0;
      InIt _sel2[2*RX::sel_len];
      if (!RX::match(it, end, _sel2, _nsel2))
        return false;

      int _nsel = 0;
      star<RX>::match(it, end, sel, _nsel);
      if (!_nsel) {
        for (int i = 0; i < _nsel2; ++i)
          sel[i] = _sel2[i];
        _nsel = _nsel2;
      }
      nsel += _nsel;
      return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return match(it, end, sel, nsel, grp_present<(!!sel_len)>());
    }

    enum {sel_len = RX::sel_len};
    enum {undoable = 1};
};

template<class RX>
struct opt {/* optional occurence of RX - like "(abc)?" */
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        RX::match(it, end);
        return true;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
    {
        RX::match(it, end, sel, nsel);
        return true;
    }

    enum {sel_len = RX::sel_len};
    enum {undoable = 1};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct seq /* sequence of RX - like "(abc)(def)" */
{
    typedef seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template <bool> struct simple{};

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, simple<true>) {
        return RX0::match(it, end) && tail::do_match(it, end);
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, simple<false>) {
      for (InIt _end = end; it != _end; --_end) {
        InIt _it = it;
        if (!RX0::match(_it, _end))
          return false;
        if (tail::do_match(_it, end)) {
          it = _it;
          return true;
        }
      }
      return false;
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end) {
      return do_match(
        it, end, simple<(!RX0::undoable || tail::end_seq)>()
      );
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, simple<true>
    ) {
      return RX0::match(it, end, sel, nsel)
          && tail::do_match(it, end, sel + 2*RX0::sel_len, nsel);
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<false>
    ) {
      for (InIt _end = end; it != _end; --_end) {
        InIt _it(it);
        if (!RX0::match(_it, _end))
          return false;
        if (tail::do_match(_it, end, sel, nsel)) {
          it = _it;
          return true;
        }
      }
      return false;
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, grp_present<true>
    ) {
      for (InIt _end = end; it != _end; --_end) {
        InIt _it(it);
        InIt _sel[RX0::sel_len + 1];
        int _nsel = 0;
        if (!RX0::match(_it, _end, _sel, _nsel))
          return false;
        if (tail::do_match(_it, end, sel + 2*RX0::sel_len, nsel)) {
          for (int i = 0; i < 2*_nsel; ++i)
            sel[i] = _sel[i];
          nsel += _nsel;
          it = _it;
          return true;
        }
      }
      return false;
    }

    template<class InIt>
    static bool do_match(
      InIt& it, const InIt& end, InIt* sel, int& nsel, simple<false>
    ) {
      return do_match(it, end, sel, nsel, grp_present<(!!RX0::sel_len)>());
    }

    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      return do_match(
        it, end, sel, nsel, simple<(!RX0::undoable || tail::end_seq)>()
      );
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end) {
      InIt itbk(it);
      bool res = do_match(it, end);
      if (!res)
        it = itbk;
      return res;
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
        InIt itbk(it);
        int nselbk = nsel;
        bool res = do_match(it, end, sel, nsel);
        if( !res ) {
            it = itbk;
            nsel = nselbk;
        }
        return res;
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
    enum {undoable = RX0::undoable || tail::undoable};
    enum {end_seq = 0};
};

template<> struct seq<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool do_match(InIt&, const InIt&)
        { return true; }
    template<class InIt>
    static bool do_match(InIt& it, const InIt& end, InIt* sel, int& nsel)
        { return true; }

    enum {sel_len = 0};
    enum {undoable = 0};
    enum {end_seq = 1};
};

template<
    class RX0,      class RX1,      class RX2=seqe, class RX3=seqe, class RX4=seqe,
    class RX5=seqe, class RX6=seqe, class RX7=seqe, class RX8=seqe, class RX9=seqe>
struct alt /* alternative - like "(abc|def)" */
{
    typedef alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,seqe> tail;

    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        if (RX0::match(it, end))
          return true;
        else
          return tail::match(it, end);
    }

    template<class InIt>
      static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
        if (RX0::match(it, end, sel, nsel))
          return true;
        else
          return tail::match(it, end, sel + 2*RX0::sel_len, nsel);
    }

    enum {sel_len = RX0::sel_len + tail::sel_len};
    enum {undoable = 1};
};

template<> struct alt<seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe,seqe>
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
        { return false; }
    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt*, int&)
        { return false; }

    enum {sel_len = 0};
    enum {undoable = 0};
};

template<class RX>
struct select
{
    template<class InIt>
    static bool match(InIt& it, const InIt& end)
    {
        return RX::match(it, end);
    }

    template<class InIt>
    static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel) {
      InIt first(it);
      int _nsel = 0;
      if (RX::match(it, end, sel + 2, _nsel)) {
        sel[0] = first;
        sel[1] = it;
        nsel += 1 + _nsel;
        return true;
      } else {
        sel[0] = sel[1] = InIt();
        return false;
      }
    }

    enum {sel_len = 1};
    enum {undoable = RX::undoable};
};

//-////////////////////////////////////////////////////////////////////////
template<bool INCLUSIVE> struct ws_
    :cc<INCLUSIVE, ' ', '\t'>
    {};
typedef ws_<true> ws;
typedef ws_<false> not_ws;

template<bool INCLUSIVE> struct digit_
    :range<'0','9',INCLUSIVE>
    {};
typedef digit_<true> digit;
typedef digit_<false> not_digit;

template<bool INCLUSIVE> struct xdigit_
    :set< range<'0','9',INCLUSIVE>, range<'A','F',INCLUSIVE>, range<'a','f',INCLUSIVE> >
    {};
typedef digit_<true> xdigit;
typedef digit_<false> not_xdigit;

template<bool INCLUSIVE> struct alpha_
    :set< range<'A','Z',INCLUSIVE>, range<'a','z',INCLUSIVE> >
    {};
typedef alpha_<true> alpha;
typedef alpha_<false> not_alpha;

template<bool INCLUSIVE> struct alphanum_
    :set< alpha_<INCLUSIVE>, digit_<INCLUSIVE> >
    {};
typedef alphanum_<true> alphanum;
typedef alphanum_<false> not_alphanum;

struct endl:seq< opt< c<'\r'> >, c<'\n'> > {};

//Shura added
struct dot {/*any character*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      bool res = (it != end);
      if( res ) ++it;
      return res;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it,end);
  }

  enum {sel_len = 0};
  enum {undoable = 0};
};//dot /*any character*/

struct ends {/*end of input sequence*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return it == end;
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt*, int&)
  {
      return match(it, end);
  }

  enum {sel_len = 0};
  enum {undoable = 0};
};//ends /*end of input sequence*/

template <class RX>
struct noundo {/*modifer for non undoable repeats*/
  template<class InIt>
  static bool match(InIt& it, const InIt& end)
  {
      return RX::match(it, end);
  }

  template<class InIt>
  static bool match(InIt& it, const InIt& end, InIt* sel, int& nsel)
  {
      return RX::match(it, end, sel, nsel);
  }
  enum {sel_len = RX::sel_len};
  enum {undoable = 0};
};//noundo

//Приверка последовательности
template <class RX, class Iter>
bool test(RX, Iter first, Iter last) {
  return RX::match(first, last) && first == last;
}

template <class RX, class String>
bool test(RX, const String& str) {
  typename str::const_iterator first = str.begin();
  return RX::match(first, str.end()) && first == str.end();
}

}//namespace static_regex
#endif//__STATIC_REGEX_H_INCLUDED__
... << RSDN@Home 1.1.0 stable >>
Re[3]: Предложения по дальнейшей разработке
От: Tonal- Россия www.promsoft.ru
Дата: 29.12.03 20:11
Оценка:
Вкралась зловредная ошибка.
Вот правильный вариант:
template <class RX, class String>
bool test(RX, const String& str) {
  typename String::const_iterator first = str.begin();
  return RX::match(first, str.end()) && first == str.end();
}
... << RSDN@Home 1.1.0 stable >>
Re: Код: версия 0.00000004
От: Аноним  
Дата: 06.01.04 18:04
Оценка:
Дофигища изменений: контейнеры для совпадений, обратные ссылки, "нежадные" и "жадные" операторы-повторители. Подробнее — отдельным письмом.

#ifndef __STATIC_REGEX_H_INCLUDED__
#define    __STATIC_REGEX_H_INCLUDED__

namespace static_regex {

typedef wchar_t rx_char;
typedef unsigned int rx_int;
struct _Sqe {};
enum { _Stc = 0xBAADC0DE };

//-////////////////////////////////////////////////////////////////////////

/**\ingroup grpSRXM
Single match.
\sa mark - capture a %submatch*/
template<class IT>
class submatch {
    rx_int id_; IT begin_; IT end_;
public:
    submatch() {}
    submatch(rx_int id, const IT& begin, const IT& end)
        :id_(id),begin_(begin),end_(end) {}
    template<class IT1> submatch(const submatch<IT1>& rhs)
        :id_(rhs.id()),begin_(rhs.begin()),end_(rhs.end()) {}
    ///get match identifier
    rx_int id() const { return id_; }
    ///get match beginning
    const IT& begin() const { return begin_; }
    ///get match ending
    const IT& end() const { return end_; }
    ///match length
    std::size_t length() const { return end_ - begin_; }
};

template<class IT, std::size_t N> class match_array;

template<class IT, std::size_t N>
void set_match_count(match_array<IT,N>& m, std::size_t cnt)
    { if(cnt > N) cnt = N; m.nmatch_ = cnt; }

template<class IT, std::size_t N>
submatch<IT>& get_match_at(match_array<IT,N>& m, std::size_t pos)
    { return m.match_[pos]; }

/**\ingroup grpSRXM
Submatch container based on static array.
\param IT iterator type
\param N  container capcity*/
template<class IT, std::size_t N=31>
class match_array {
    match_array(const match_array&);
    match_array& operator=(const match_array&);
public:
    typedef submatch<IT> match_type;
    typedef const match_type* iterator;
public:
    match_array()
        :nmatch_(0) {}
    explicit match_array(std::size_t)
        :nmatch_(0) {}
public:
    std::size_t size() const
        { return nmatch_; }
    match_array& reset()
        { nmatch_ = 0; return *this; }
    const match_type& operator[](std::size_t pos) const
        { return match_[pos]; }
    iterator begin() const { return match_; }
    iterator end() const { return match_ + nmatch_; }
private:
    match_type match_[N+1];
    std::size_t nmatch_;

#if defined(_MSC_VER) && _MSC_VER < 1300 //MSVC 6.0
    friend void set_match_count(match_array& m, std::size_t cnt);
    friend submatch<IT>& get_match_at(match_array& m, std::size_t pos);
#else
    friend void set_match_count<>(match_array& m, std::size_t cnt);
    friend submatch<IT>& get_match_at<>(match_array& m, std::size_t pos);
#endif//MSVC 6.0
};

template<class IT, class A> class match_vector;

template<class IT, class A>
void set_match_count(match_vector<IT,A>& m, std::size_t cnt)
    { m.resize(cnt); }

template<class IT, class A>
submatch<IT>& get_match_at(match_vector<IT,A>& m, std::size_t pos)
    { return m.at(pos); }

/**\ingroup grpSRXM
Submatch container based on std::vector.
\param IT iterator type
\param A  allocator type*/
template<class IT, class A=std::allocator< submatch<IT> > >
class match_vector
    :std::vector<submatch<IT>,A>
{
    match_vector(const match_vector&);
    match_vector& operator=(const match_vector&);
    typedef std::vector<submatch<IT>,A> base;
public:
    typedef submatch<IT> match_type;
    typedef typename base::const_iterator iterator;
public:
    match_vector()
        {}
    explicit match_vector(std::size_t size)
        { base::reserve(size); }
public:
    using base::size;

    match_vector& reset()
        { base::resize(0); return *this; }
    const match_type& operator[](std::size_t pos) const
        { return base::at(pos); }
    iterator begin() const { return base::begin(); }
    iterator end() const { return base::end(); }

#if defined(_MSC_VER) && _MSC_VER < 1300 //MSVC 6.0
    friend void set_match_count(match_vector& m, std::size_t cnt);
    friend submatch<IT>& get_match_at(match_vector& m, std::size_t pos);
#else
    friend void set_match_count<>(match_vector& m, std::size_t cnt);
    friend submatch<IT>& get_match_at<>(match_vector& m, std::size_t pos);
#endif//MSVC 6.0
};

//-////////////////////////////////////////////////////////////////////////
#define _SRX_NULLABLE(b) \
    enum{ is_nullable = (b) }

struct _Norx {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return false; }
};

/**\ingroup grpSRXL
Literal string - up to 30 symbols */
template<
    rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
    rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
    rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct s {
    typedef s<c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,
c23,c24,c25,c26,c27,c28,c29,_Stc> tail;

    _SRX_NULLABLE(false);

    enum { length = 1 + tail::length };

    template<class InIt>
    static bool do_match(InIt& it)
        { return (c0 == static_cast<rx_char>(*it)) && tail::do_match(++it); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt tend( it + length );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it);
        bool res = do_match(it);
        if( !res ) it = t;
        return res;
    }
};
template<> struct s<
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc>
{
    enum { length = 0 };

    template<class InIt>
    static bool do_match(InIt&)
        { return true; }
};

/**\ingroup grpSRXL
Single literal charachter */
template<rx_char E>
struct c {
    _SRX_NULLABLE(false);

    static bool char_match(rx_char ch)
        { return (E == ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        bool res = (it != end) && (E == static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }
};

/**\ingroup grpSRXL
Charachter class - like \c "[abcdEF]" or \c "[^abcdEF]"*/
template<
    bool INCLUSIVE,
    rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
    rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
    rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct cc_ {
    typedef cc_<INCLUSIVE,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,
c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,_Stc> tail;

    _SRX_NULLABLE(false);

    static bool char_match_(rx_char ch)
        { return (c0 == ch) || tail::char_match_(ch); }
    static bool char_match(rx_char ch)
        { return INCLUSIVE ? char_match_(ch) : !char_match_(ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES&)
    {
        bool res = (it != end) && 
            char_match(static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }
};
template<> struct cc_<true,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc>
{ 
    static bool char_match_(rx_char ch)
        { return false; }
};
template<> struct cc_<false,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc,
    _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc, _Stc>
{
    static bool char_match_(rx_char ch)
        { return false; }
};

/**\ingroup grpSRXL
Charachter class - like \c "[abcdEF]"*/
template<
rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct cc:cc_<true,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,
c21,c22,c23,c24,c25,c26,c27,c28,c29> {};

/**\ingroup grpSRXL
Charachter class - like \c "[^abcdEF]"*/
template<
rx_int c0,       rx_int c1,       rx_int c2 =_Stc, rx_int c3 =_Stc, rx_int c4 =_Stc, rx_int 
c5 =_Stc, rx_int c6 =_Stc, rx_int c7 =_Stc, rx_int c8 =_Stc, rx_int c9 =_Stc,
rx_int c10=_Stc, rx_int c11=_Stc, rx_int c12=_Stc, rx_int c13=_Stc, rx_int c14=_Stc, rx_int 
c15=_Stc, rx_int c16=_Stc, rx_int c17=_Stc, rx_int c18=_Stc, rx_int c19=_Stc,
rx_int c20=_Stc, rx_int c21=_Stc, rx_int c22=_Stc, rx_int c23=_Stc, rx_int c24=_Stc, rx_int 
c25=_Stc, rx_int c26=_Stc, rx_int c27=_Stc, rx_int c28=_Stc, rx_int c29=_Stc>
struct not_cc:cc_<false,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,
c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29> {};

/**\ingroup grpSRXL
Charachter range - like \c "[a-d]" or \c "[^a-d]" */
template<rx_char F, rx_char B, bool INCLUSIVE=true>
struct cr {
    _SRX_NULLABLE(false);

    static bool char_match_(rx_char ch)
        { return (((F < B) ? F : B) <= ch) && (ch <= ((F < B) ? B : F)); }
    static bool char_match(rx_char ch)
        { return INCLUSIVE ? char_match_(ch) : !char_match_(ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES&)
    {
        bool res = (it != end) && 
            char_match(static_cast<rx_char>(*it));
        if( res ) ++it;
        return res;
    }
};

/**\ingroup grpSRXL
Charachter set - a combination of two or more charachter set classes.
\param CC0-CC9 charachter set classes
\sa charachter set classes: c, cc, cr, cs */
template<
    class CC0,      class CC1,      class CC2=_Sqe, class CC3=_Sqe, class CC4=_Sqe, 
    class CC5=_Sqe, class CC6=_Sqe, class CC7=_Sqe, class CC8=_Sqe, class CC9=_Sqe>
struct cs {
    typedef cs<CC1,CC2,CC3,CC4,CC5,CC6,CC7,CC8,CC9,_Sqe> tail;

    _SRX_NULLABLE(false);

    static bool char_match(rx_char ch)
        { return CC0::char_match(ch) || tail::char_match(ch); }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        bool res = (it != end) &&
            char_match( static_cast<rx_char>(*it) );
        if( res ) ++it;
        return res;
    }
};
template<> struct cs<_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe> { 
    static bool char_match(rx_char)
        { return false; }
};

/**\ingroup grpSRXO
Zero or more occurences of \c RX - like \c "(abc)*"
\param RX regular expression class*/
template<class RX>
struct star {
    _SRX_NULLABLE(true);
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { while( RX::match(it,end,m) ); return true; }
};

/**\ingroup grpSRXO
One or more occurences of \c RX - like \c "(abc)+"
\param RX regular expression class*/
template<class RX>
struct plus {
    _SRX_NULLABLE(false);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::match(it,end,m) && star<RX>::match(it,end,m); }
};

/**\ingroup grpSRXO
Optional occurence of RX - like \c "(abc)?"
\param RX regular expression class*/
template<class RX>
struct opt {
    _SRX_NULLABLE(true);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { RX::match(it,end,m); return true; }
};

/**\ingroup grpSRXO
Repetition - like \c "(abc){3,5}"
\param RX regular expression class
\param N1 number of times \c RX \em must be matched 
\param N2 number of times \c RX \em may match - must be greater or equal to \c N1*/
template<std::size_t N1, std::size_t N2, class RX>
struct rep {
    _SRX_NULLABLE(( N1==0 ));
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        std::size_t n, nmbk = m.size();
        InIt itbk(it);

        n = N1;
        while( n && RX::match(it,end,m) ) --n;
        if( n ) { it = itbk; set_match_count(m,nmbk); return false; }

        n = N2 - N1;
        while( n && RX::match(it,end,m) ) --n;
        return true;
    }
};

template<class RX> struct _Sqtw:RX {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::do_match(it,end,m); }
};

template<class M,class N,class U>
struct _Sqmw:M {
    typedef N rx_next;
    typedef U rx_unext;
};

/**\ingroup grpSRXO
Sequence of expressions - like \c "(abc)(def)"
\param RX0-RX9 regular expression class*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct seq {
    typedef _Sqtw< seq<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,_Sqe> > tail;

    _SRX_NULLABLE(RX0::is_nullable && tail::is_nullable);
    enum { is_end = false };

    template<class InIt, class MATCHES>
    static bool do_match(InIt& it, const InIt& end, MATCHES& m)
    { 
        typedef typename MATCHES::match_container mc;
        typedef typename MATCHES::rx_unext rxun;
        if( tail::is_end ) {
            typedef _Sqmw<mc, rxun, _Norx> mw;
            return RX0::match(it,end,reinterpret_cast<mw&>(m));
        } else {
            typedef _Sqmw<mc, tail, rxun> mw;
            return RX0::match(it, end, reinterpret_cast<mw&>(m)) && tail::do_match(it,end,m);
        }
    }

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt itbk(it);
        std::size_t nmbk = m.size();

        typedef typename MATCHES::match_container mc;
        typedef typename MATCHES::rx_next rxn;
        typedef _Sqmw<mc, _Norx, rxn> mw;    
        bool res = do_match(it, end, reinterpret_cast<mw&>(m));

        if( !res ) { it = itbk;    set_match_count(m,nmbk); }
        return res;
    }
};
template<> struct seq<_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe> {
    _SRX_NULLABLE(true);
    enum { is_end = true };
    template<class InIt, class MATCHES> 
    static bool do_match(InIt& it, const InIt& end, MATCHES& m)
        { return true; }
};

/**\ingroup grpSRXO
Alternative - like \c "(abc|def)"
\param RX0-RX9 regular expression class*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct alt {
    typedef alt<RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9,_Sqe> tail;

    _SRX_NULLABLE(RX0::is_nullable || tail::is_nullable);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt rxit(it); 
        std::size_t nmbk = m.size(), rxnm = nmbk;
        
        bool res = RX0::match(rxit,end,m);
        if( res ) rxnm = m.size();
        res |= tail::match(it,end,m);

        if( it < rxit || it == rxit ) {
            it = rxit;
            set_match_count(m,rxnm);
        } else
        if( res ) {
            std::size_t delta = rxnm - nmbk;
            if( delta ) {
                std::size_t count = m.size() - rxnm;
                for( ; count; ++nmbk, --count )
                    get_match_at(m,nmbk) = get_match_at(m,nmbk+delta);
                set_match_count(m,m.size()-delta);
            }
        }
        return res;
    }
};
template<> struct alt<_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe,_Sqe> {
    _SRX_NULLABLE(false);
    template<class InIt, class MATCHES> static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return false; }
};

/**\ingroup grpSRXO
Submatch marker
\param ID match identifier
\param RX regular expression to capture into match container
\sa 
    match - class used to capture single %match \n
    match_array - %match container based on static array \n
    match_vector - %match container based on std::vector*/
template<rx_int ID, class RX>
struct mark {
    _SRX_NULLABLE(RX::is_nullable);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        InIt first(it);
        std::size_t nmbk = m.size();
        set_match_count(m,m.size()+1);
        bool res = RX::match(it,end,m);
        if( res && first != it ) {
            typedef typename MATCHES::match_type mt;
            get_match_at(m,nmbk) = mt(ID,first,it);
        } else
            set_match_count(m,nmbk);
        return res;
    }
};

/**\ingroup grpSRXO
Backreference - like <code>"(sense|response) and \\1bility"</code>
\param ID match identifier to refer*/
template<rx_int ID>
struct bk {
    _SRX_NULLABLE(true);

    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        typename MATCHES::iterator r = m.end();
        if( r == m.begin() ) return false;
        while( true ) {
            if( ID == (--r)->id() ) break;
            if( r == m.begin() ) return false;
        }

        InIt tend( it + (r->end() - r->begin()) );
        if( !(tend < end || tend == end) )
            return false;

        InIt t(it), s(r->begin());
        while( s < r->end() )    {
            if( *s != *t ) return false;
            ++s; ++t;
        }
        it = t;
        return true;
    }
};

/**\ingroup grpSRXO
non-greedy version of operator \c star<> */
template<class RX>
struct xstar:star<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        typedef typename MATCHES::rx_next rx_next;
        do {
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( rx_next::match(t,end,m) )
                { set_match_count(m,nmbk); break; }
        } while( RX::match(it,end,m) );
        return true;
    }
};

template<class RX>
struct xxstar:star<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        typedef typename MATCHES::rx_next rx_next;
        std::size_t next_nm;
        bool here_matched, next_matched=false;
        InIt next_pos(it);
        do {
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( here_matched = rx_next::match(t,end,m) ) {
                next_matched = true;
                next_pos = it;
                set_match_count(m,next_nm = nmbk);
            }
        } while( RX::match(it,end,m) );
        if( !here_matched && next_matched ) 
            { it = next_pos; set_match_count(m,next_nm); }
        return true;
    }
};

/**\ingroup grpSRXO
non-greedy version of operator \c plus<> */
template<class RX>
struct xplus:plus<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::match(it,end,m) && xstar<RX>::match(it,end,m); }
};

template<class RX>
struct xxplus:plus<RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return RX::match(it,end,m) && xxstar<RX>::match(it,end,m); }
};

/**\ingroup grpSRXO
non-greedy version of operator \c rep<>*/
template<std::size_t N1, std::size_t N2, class RX>
struct xrep:rep<N1,N2,RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        if( !rep<N1,N1,RX>::match(it,end,m) )
            return false;

        typedef typename MATCHES::rx_next rx_next;
        std::size_t n = N2 - N1;
        do {
            if( 0 == n-- ) break;
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( rx_next::match(t,end,m) )
                { set_match_count(m,nmbk); break; }
        } while( RX::match(it,end,m) );
        return true;
    }
};

template<std::size_t N1, std::size_t N2, class RX>
struct xxrep:rep<N1,N2,RX> {
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
    {
        if( !rep<N1,N1,RX>::match(it,end,m) )
            return false;

        typedef typename MATCHES::rx_next rx_next;
        std::size_t next_nm;
        bool here_matched = true, next_matched = false;
        InIt next_pos(it);
        std::size_t n = N2 - N1;
        do {
            if( 0 == n-- ) break;
            InIt t(it); 
            std::size_t nmbk = m.size();
            if( here_matched = rx_next::match(t,end,m) ) {
                next_matched = true;
                next_pos = it;
                set_match_count(m,next_nm = nmbk);
            }
        } while( RX::match(it,end,m) );
        if( !here_matched && next_matched ) 
            { it = next_pos; set_match_count(m,next_nm); }
        return true;
    }
};

//-////////////////////////////////////////////////////////////////////////
/**\ingroup grpSRXO
\link static_regex::star star\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct star_:star<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xstar xstar\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xstar_:xstar<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xxstar xxstar\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xxstar_:xxstar<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::plus plus\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct plus_:plus<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xplus xplus\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xplus_:xplus<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xxplus xxplus\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xxplus_:xxplus<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::rep rep\endlink operator with multiple arguments*/
template<
    std::size_t N1, std::size_t N2,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct rep_:rep<N1,N2,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xrep xrep\endlink operator with multiple arguments*/
template<
    std::size_t N1, std::size_t N2,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xrep_:xrep<N1,N2,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::xxrep xxrep\endlink operator with multiple arguments*/
template<
    std::size_t N1, std::size_t N2,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct xxrep_:xxrep<N1,N2,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::opt opt\endlink operator with multiple arguments*/
template<
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct opt_:opt<seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

/**\ingroup grpSRXO
\link static_regex::mark mark\endlink operator with multiple arguments*/
template<
    rx_int ID,
    class RX0,      class RX1,      class RX2=_Sqe, class RX3=_Sqe, class RX4=_Sqe, 
    class RX5=_Sqe, class RX6=_Sqe, class RX7=_Sqe, class RX8=_Sqe, class RX9=_Sqe>
struct mark_:mark<ID,seq<RX0,RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8,RX9> > {};

//-////////////////////////////////////////////////////////////////////////
// Often-used primitives
template<bool INCLUSIVE> struct ws_:cc<INCLUSIVE, ' ', '\t'>{};
struct ws:ws_<true>{};

template<bool INCLUSIVE> struct digit_:cr<'0','9',INCLUSIVE>{};
struct digit:digit_<true>{};

template<bool INCLUSIVE> struct xdigit_:cs< cr<'0','9',INCLUSIVE>, cr<'A','F',INCLUSIVE>, 
cr<'a','f',INCLUSIVE> >{};
struct xdigit:xdigit_<true>{};

template<bool INCLUSIVE> struct alpha_:cs< cr<'A','Z',INCLUSIVE>, cr<'a','z',INCLUSIVE> >{};
struct alpha:alpha_<true>{};

template<bool INCLUSIVE> struct alphanum_:cs< alpha_<INCLUSIVE>, digit_<INCLUSIVE> >{};
struct alphanum:alphanum_<true>{};

struct eol:seq<opt<c<'\r'> >, c<'\n'> >{};

struct eos {
    _SRX_NULLABLE(true);
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return it == end; }
};

struct dot {
    _SRX_NULLABLE(false);
    template<class InIt, class MATCHES>
    static bool match(InIt& it, const InIt& end, MATCHES& m)
        { return (it != end) ? (++it, true) : false; }
};

//-////////////////////////////////////////////////////////////////////////
template<class IT> class _NoMatches {
    _NoMatches() {}
public:
    typedef submatch<IT> match_type;
    typedef const match_type* iterator;
    typedef _NoMatches match_container;
    typedef _Norx rx_unext;
    typedef _Norx rx_next;
public:
    std::size_t size() const { return 0; }
    iterator begin() const { return 0; }
    iterator end() const { return 0; }
    static _NoMatches<IT>& _Get() { static _NoMatches<IT> m; return m; }
};

template<class IT>
void set_match_count(_NoMatches<IT>& m, std::size_t cnt)
    {}

template<class IT>
submatch<IT> get_match_at(_NoMatches<IT>& m, std::size_t pos)
    { return submatch<IT>(); }

template<class M> struct _Mmw:M {
    typedef _Mmw match_container;
    typedef _Norx rx_unext;
    typedef _Norx rx_next;
};

template<class RX, class InIt>
inline bool match(InIt& it, const InIt& end)
    { return RX::match(it,end, _NoMatches<InIt>::_Get()); }

template<class RX, class InIt, class MATCHES>
inline bool match(InIt& it, const InIt& end, MATCHES& m)
{ 
    typedef _Mmw<MATCHES> mw;
    return RX::match(it,end,reinterpret_cast<mw&>(m.reset())); 
}

}//namespace static_regex

#undef _SRX_NULLABLE
#endif//__STATIC_REGEX_H_INCLUDED__
Re[2]: Код: версия 0.00000004 - изменения
От: Аноним  
Дата: 06.01.04 19:16
Оценка:
-переименования
-- range<> --> cr<> (мнемоника — "char range")
-- set<> --> cs<> (мнемоника — "char sange")
-- select<> --> mark<> (конфликты с gcc)

-убраны операторы начинающиеся с "not_" — вместо них используйте "name_<false", где "name" — имя оператора. Например not_cc<A,B,C> == cc_<false,A,B,C>

-добавлены многоаргументные версии для всех нетерминальных операторов (т.е. star, plus, opt, и тд) — их имена также заканчиваются на "_"

-у оператора захвата подсовпадения mark<int ID, class RX> появился параметр ID — это произвольный числовой идентификатор подсовпадения.

-Нельзя пользоваться member-функцией RX::match() — она стала насколько мохнатой, что пришлось ввести глобальные функции match().
Их надо использовать так:
static_regex::match_array<> matches;
bool matched = static_regex::match<myregex>(start, end, matches);//или..
bool matched = static_regex::match<myregex>(start, end);//или..


-Теперь библиотека использeт контейнеры для хранения подсовпадений. Доступно 2 вида контейнеров:
-- match_array<class InIt,int N> — контейнер основанный на статическом массиве размера N. Если подсовпадений больше чем размер контейнера, то "лишние" подсовпадения игнорируются.
-- match_array<class InIt> — контейнер основанный на std::vector<>.
-- более подробно, смотрите эти классы и класс submatch в исходниках.
Пример использования:
template<class RX> void test(char* pp)
{
    typedef pxt::static_regex::match_array<char*>  MC;
//  typedef pxt::static_regex::match_vector<char*> MC;    
    MC mc;

    char* p = pp;
    bool res = pxt::static_regex::match<RX>(p, p+strlen(p), mc);
    printf("%smatched: %s\n", res?"":"not ", pp);
    if( res ) {
        printf("\t{%.*s}%s\n", p - pp, pp, p);    
        printf("\t");
        for(MC::iterator i=mc.begin(); i!=mc.end(); ++i)
            printf("{%d:%.*s}", i->id(), i->length(), i->begin());    
        printf("\n");
    }
}


-Добавлен оператор "обратной ссылки" bk<int ID>
Пример использования (псевдокод)
typedef seq<mark<1,cc<'\'','"'>>, s<"HELLO">, bk<1>> myrx;
//myrx совпадет со строкой "HELLO" и со строкой 'HELLO'


-к ранее имевшимся "тупым" операторам-повторителям star<>, plus<>, rep<> добавлены следующие их модификации:
-- "нежадные": xstar<>, xplus<>, xrep<>
Пример использования (псевдокод)
typedef seq<mark<1,plus<dot>>, mark<2,s<".cpp">>>  myrx1;
typedef seq<mark<1,xplus<dot>>, mark<2,s<".cpp">>> myrx2;
//myrx2 совпадет со строкой "file1.cpp", а myrx1 - нет, 
//т.к. оператор plus<dot> сьест все до конца строки.

-- "жадные": xxstar<>, xxplus<>, xxrep<>
Пример использования (псевдокод)
typedef seq<mark<1,xxplus<dot>>, mark<2,s<".cpp">>> myrx3;
//при проверке строки "file1.cpp.cpp.cpp.cpp"
//myrx2 совпадет с подстрокой "file1.cpp", а myrx3 - с полной строкой,

Внимание: использование этих модификаций влечет за собой значительное падение производительности. "нежадных" — примерно в 2 раза, "жадных" — в десятки раз.

-Бенчмарки
Не улучшились, но и не ухудшились.
Был также проведен тест на производительность "жадных" операторов.
выражение "(.+)(\.cpp)" проверялось на строке "file.cpp.cpp.cpp.cpp" длиной 4 мегабайта. boost::regex оказалась хуже в 10 раз...
Re[3]: Код: версия 0.00000004 - изменения
От: Аноним  
Дата: 07.01.04 06:54
Оценка:
Здравствуйте, Аноним, Вы писали:

А>-переименования

А>-- set<> --> cs<> (мнемоника — "char sange")

Хмм, sange...

Keep up good work
Re[2]: Некоторые замечания по коду 4
От: Tonal- Россия www.promsoft.ru
Дата: 29.01.04 23:25
Оценка:
Наверное надо включить #include <vector> если есть элементы зависимые от std::vector.

Не совсем понятно назначение функций get_match_at и set_match_count. Почму нельзя просто воспользоваться методами operator[]() и resize(). Тогда не понадобятся friend объявления, которые во первых не совсем тривиальны для шаблонов, а во вторых разные компиляторы их по разному трактуют (Borland например требует полной спецификации шаблонных параметров.)

По моему operator[]() для match_vector и для match_array несколько расходятся. Если уж проверять выход за граници, то для обоих, или уж не проверять совсем. А так как-то не согласованно получается.
Я бы не проверял (по крайний мере в релизе).

Начитался давеча Саттера — он говорит что не следует применять наследование без вестких на то причин — это я о match_vector. Собственно если переименовать функцию reset() в clear() то вместо match_vector можно будет использовать и std::vector, и std::deque и boost::array. В общем непонятна суть ограничений.

Есть некоторый недостаток в ID к mark-у: непонятно как избежать совподения. Оно может случиться не только из за ошибок набивки, но и в случаи собирания выражения из разных частей. ;-с

По моему было бы очень удобно, если для любого вырожения можно было бы получить максимальное количество подсовпадений. Реализация — тривиальна: для символьных классов = 0, для mark = подвырожение + 1, для контейнеров = сумма подвырожений.

Может быть следует предоставить 2 формы alt — полный перебор (POSIX-like), или до первого совпадения (Perl-like) — некоторые выражения можно соптимизировать.

Ну вроде на первый взгляд всё, спать пора. ;-в
... << RSDN@Home 1.1.0 stable >>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.