crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> c-stype string format for cpp, %d, %s и безо всяких бустов
Andrew Selivanov
  опции профиля:
сообщение 22.4.2008, 17:31
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 249
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 3

Спасибо сказали: 15 раз(а)




Репутация:   6  


Отрыл любопытнейший исходник, если коротко, то относительно просто можно ввести форматирование строки как в старом добром C (аля printf):
cout << c_format("test: %d", 100) << endl;
Вначале моя "all-in-one" сборка в одном cpp файле и в конце - оригинал из XORP.
c_format.cpp
#include <iostream>
#include <vector>
#include <cstdarg>
using namespace std;

#ifndef HOST_OS_WINDOWS
#define HAVE_C99_SNPRINTF    // [v]snprintf() conforms to ISO C99 spec
#endif

#define FORMAT_BUFSIZE    4096

#define c_format(format, args...)                           \
    (c_format_validate(format, arg_count(args)), do_c_format(format, ## args))

inline int arg_count() { return 0; }

template <class A>
inline int arg_count(A) { return 1; }

template <class A, class B>
inline int arg_count(A,B) { return 2; }

template <class A, class B, class C>
inline int arg_count(A,B,C) { return 3; }

template <class A, class B, class C, class D>
inline int arg_count(A,B,C,D) { return 4; }

template <class A, class B, class C, class D, class E>
inline int arg_count(A,B,C,D,E) { return 5; }

template <class A, class B, class C,class D, class E, class F>
inline int arg_count(A,B,C,D,E,F) { return 6; }

template <class A, class B, class C, class D, class E, class F, class G>
inline int arg_count(A,B,C,D,E,F,G) { return 7; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H>
inline int arg_count(A,B,C,D,E,F,G,H) { return 8; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I>
inline int arg_count(A,B,C,D,E,F,G,H,I) { return 9; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J>
inline int arg_count(A,B,C,D,E,F,G,H,I,J) { return 10; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K) { return 11; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K, class L>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L) { return 12; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K, class L, class M>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M) { return 13; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K, class L, class M, class N>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M,N) { return 14; }

void c_format_validate(const char* fmt, int n);

#if defined(__printflike)
string do_c_format(const char* fmt, ...) __printflike(1,2);
#elif (defined(__GNUC__))
string do_c_format(const char* fmt, ...)
    __attribute__((__format__(printf, 1, 2)));
#else
string do_c_format(const char* fmt, ...);
#endif

void
c_format_validate(const char* fmt, int exp_count)
{
    const char *p = fmt;
    int state = 0;
    int count = 0;
    
    while(*p != 0) {
    if (state == 0) {
        if (*p == '%') {
        count++;
        state = 1;
        }
    } else {
        switch (*p) {
        case 'd':
        case 'i':
        case 'o':
        case 'u':
        case 'x':
        case 'X':
        case 'D':
        case 'O':
        case 'U':
        case 'e':
        case 'E':
        case 'f':
        case 'g':
        case 'G':
        case 'c':
        case 's':
        case 'p':
        //parameter type specifiers
        state = 0;
        break;
        case '%':
        //escaped percent
        state = 0;
        count--;
        break;
        case 'n':
        //we don't permit %n
        fprintf(stderr, "%%n detected in c_format()\n");
        abort();
        case '*':
        //field width or precision also needs a parameter
        count++;
        break;
        }
    }
    p++;
    }
    if (exp_count != count) {
    abort();
    }
}

string
do_c_format(const char* fmt, ...)
{
    size_t buf_size = FORMAT_BUFSIZE;             // Default buffer size
    vector<char> b(buf_size);
    va_list ap;

    do {
    va_start(ap, fmt);
    int ret = vsnprintf(&b[0], buf_size, fmt, ap);
#ifndef HAVE_C99_SNPRINTF
    // We have an evil vsnprintf() implementation (MSVC)
    if (ret != -1 && ((size_t)ret < buf_size)) {
        string r = string(&b[0]);    // Buffer size is OK
        va_end(ap);
        return r;
    }
    buf_size += FORMAT_BUFSIZE;
#else    // HAVE_C99_SNPRINTF
    // We have a C99 compliant implementation
    if ((size_t)ret < buf_size) {
        string r = string(&b[0]);    // Buffer size is OK
        va_end(ap);
        return r;
    }
    buf_size = ret + 1;        // Add space for the extra '\0'
#endif    // HAVE_C99_SNPRINTF
    b.resize(buf_size);
    } while (true);

//    XLOG_UNREACHABLE();
}

int main()
{    
    cout << c_format("test: %d", 100) << endl;
    
    return 0;
}


Исходник из проекта XORP:
c_format.hh
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-

// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.

// $XORP: xorp/libxorp/c_format.hh,v 1.10 2007/02/16 22:46:15 pavlin Exp $

#ifndef __LIBXORP_C_FORMAT_HH__
#define __LIBXORP_C_FORMAT_HH__

#include "libxorp/xorp.h"


//
// c_format is a macro that creates a string from a c-style format
// string.  It takes the same arguments as printf, but %n is illegal and
// will cause abort to be called.
//
// Pseudo prototype:
//     string c_format(const char* format, ...);
//
// In practice c_format is a nasty macro, but by doing this we can check
// the compile time arguments are sane and the run time arguments.
//

#define c_format(format, args...)                           \
    (c_format_validate(format, arg_count(args)), do_c_format(format, ## args))

//
// Template magic to allow us to count the number of varargs passed to
// the macro c_format.  We could also count the size of the var args data
// for extra protection if we were doing the formatting ourselves...
//

// Comment this out to find unnecessary calls to c_format()
inline int arg_count() { return 0; }


template <class A>
inline int arg_count(A) { return 1; }

template <class A, class B>
inline int arg_count(A,B) { return 2; }

template <class A, class B, class C>
inline int arg_count(A,B,C) { return 3; }

template <class A, class B, class C, class D>
inline int arg_count(A,B,C,D) { return 4; }

template <class A, class B, class C, class D, class E>
inline int arg_count(A,B,C,D,E) { return 5; }

template <class A, class B, class C,class D, class E, class F>
inline int arg_count(A,B,C,D,E,F) { return 6; }

template <class A, class B, class C, class D, class E, class F, class G>
inline int arg_count(A,B,C,D,E,F,G) { return 7; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H>
inline int arg_count(A,B,C,D,E,F,G,H) { return 8; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I>
inline int arg_count(A,B,C,D,E,F,G,H,I) { return 9; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J>
inline int arg_count(A,B,C,D,E,F,G,H,I,J) { return 10; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K) { return 11; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K, class L>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L) { return 12; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K, class L, class M>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M) { return 13; }

template <class A, class B, class C, class D, class E, class F, class G,
      class H, class I, class J, class K, class L, class M, class N>
inline int arg_count(A,B,C,D,E,F,G,H,I,J,K,L,M,N) { return 14; }

void c_format_validate(const char* fmt, int n);

#if defined(__printflike)
string do_c_format(const char* fmt, ...) __printflike(1,2);
#elif (defined(__GNUC__))
string do_c_format(const char* fmt, ...)
    __attribute__((__format__(printf, 1, 2)));
#else
string do_c_format(const char* fmt, ...);
#endif

#endif // __LIBXORP_C_FORMAT_HH__


c_format.cc
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-

// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.

#ident "$XORP: xorp/libxorp/c_format.cc,v 1.12 2007/02/16 22:46:15 pavlin Exp $"

#include "libxorp_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"

#include <vector>

#include "c_format.hh"


#ifndef HOST_OS_WINDOWS
#define HAVE_C99_SNPRINTF    // [v]snprintf() conforms to ISO C99 spec
#endif

#define FORMAT_BUFSIZE    4096

void
c_format_validate(const char* fmt, int exp_count)
{
    const char *p = fmt;
    int state = 0;
    int count = 0;
    
    while(*p != 0) {
    if (state == 0) {
        if (*p == '%') {
        count++;
        state = 1;
        }
    } else {
        switch (*p) {
        case 'd':
        case 'i':
        case 'o':
        case 'u':
        case 'x':
        case 'X':
        case 'D':
        case 'O':
        case 'U':
        case 'e':
        case 'E':
        case 'f':
        case 'g':
        case 'G':
        case 'c':
        case 's':
        case 'p':
        //parameter type specifiers
        state = 0;
        break;
        case '%':
        //escaped percent
        state = 0;
        count--;
        break;
        case 'n':
        //we don't permit %n
        fprintf(stderr, "%%n detected in c_format()\n");
        abort();
        case '*':
        //field width or precision also needs a parameter
        count++;
        break;
        }
    }
    p++;
    }
    if (exp_count != count) {
    abort();
    }
}

string
do_c_format(const char* fmt, ...)
{
    size_t buf_size = FORMAT_BUFSIZE;             // Default buffer size
    vector<char> b(buf_size);
    va_list ap;

    do {
    va_start(ap, fmt);
    int ret = vsnprintf(&b[0], buf_size, fmt, ap);
#ifndef HAVE_C99_SNPRINTF
    // We have an evil vsnprintf() implementation (MSVC)
    if (ret != -1 && ((size_t)ret < buf_size)) {
        string r = string(&b[0]);    // Buffer size is OK
        va_end(ap);
        return r;
    }
    buf_size += FORMAT_BUFSIZE;
#else    // HAVE_C99_SNPRINTF
    // We have a C99 compliant implementation
    if ((size_t)ret < buf_size) {
        string r = string(&b[0]);    // Buffer size is OK
        va_end(ap);
        return r;
    }
    buf_size = ret + 1;        // Add space for the extra '\0'
#endif    // HAVE_C99_SNPRINTF
    b.resize(buf_size);
    } while (true);

    XLOG_UNREACHABLE();
}

#ifdef TESTING_C_FORMAT_123
int main(int, char**)
{
    c_format("%d", 3);

    printf("%s", c_format("hello%%\n").c_str());
    printf("%s", c_format("hello %d\n", 27).c_str());
    printf("%s", c_format("hello %3d %%%s\n", 27, "xyz").c_str());
    printf("%s", c_format("hello %*d %%%s\n", 5, 27, "xyz").c_str());
    printf("%s", c_format("hello %%%*n\n").c_str());
}
#endif // TESTING_C_FORMAT_123


Сообщение отредактировал Andrew Selivanov - 22.4.2008, 17:34
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 22.4.2008, 18:41
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


что-то я ниче не понял, для чего это?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 23.4.2008, 7:56
Сообщение #3


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Litkevich Yuriy, это для извращенцев вроде меня. :)
А вообще просто для понимая как и что можно реализовать, век живи век учись.

Andrew Selivanov, жестко автор завернул. :)

Сообщение отредактировал ViGOur - 23.4.2008, 7:56
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Tonal
  опции профиля:
сообщение 23.4.2008, 8:14
Сообщение #4


Активный участник
***

Группа: Участник
Сообщений: 452
Регистрация: 6.12.2007
Из: Новосибирск
Пользователь №: 34

Спасибо сказали: 69 раз(а)




Репутация:   17  


Какой ништяк! :)
Цитата(Andrew Selivanov @ 22.4.2008, 21:31) *
///...
c_format_validate(const char* fmt, int exp_count)
{
///...
    if (exp_count != count) {
    abort();
    }
}

Цитата
А если бы ты нёс патроны! :diablo: (с) Не помню чьё


Сообщение отредактировал Tonal - 23.4.2008, 8:14
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Andrew Selivanov
  опции профиля:
сообщение 23.4.2008, 10:11
Сообщение #5


Участник
**

Группа: Участник
Сообщений: 249
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 3

Спасибо сказали: 15 раз(а)




Репутация:   6  


Цитата(Tonal @ 23.4.2008, 9:14) *
Какой ништяк! :)
Цитата(Andrew Selivanov @ 22.4.2008, 21:31) *
///...
c_format_validate(const char* fmt, int exp_count)
{
///...
    if (exp_count != count) {
    abort();
    }
}

Цитата
А если бы ты нёс патроны! :diablo: (с) Не помню чьё


:) А если бы он вез патроны? (с) Непридуманная История
Ну да, это автор конечно погорячился, но я хотел обратить внимание на использование __attribute__ и "template magic" (конкретнее: определение количества параметров в функции с помощью шаблона).
Особенно меня конечно порадовало последнее, т.к. насколько я знаю в C++ пока нет возможности передавать в шаблон произвольное количество параметров списком (C++ Templates, The Complete Guide, Chapter 13 "Future directions" P13.13 "List Parameters") а такой хак как в сорце, это реальный выход :)

Кстати, Boost.Format использует нечто похожее.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.3.2024, 15:58