Tuple для C++. Хотим оценок.
От: MikelSV http://www.centerix.ru
Дата: 04.04.11 05:11
Оценка: -2 :))
[Это перепост темы, по просьбам трудящихся, из форума исходники. За два дня на нее не было ни одного ответа, которых так хотелось. В следствии чего была высказана мысль написать еще раз в форум c++.
Я и несколько товарищей надеемся узнать мнение РСДН по данному коду.
Основной аргумент против этого кода: он не нужен, есть boost::tuple.
Я отбиваюсь тем, что мой код проще и ближе к реализации Tuple, как это сделано в D. И не требует написания лишнего кода.
Два основных вопроса: нужен ли данный код и можно ли его использовать в реальных задачах?
]

Дата: 02.04.11 13:34
Вчера совершенно случайно начали обсуждать tuple и их реализацию в С++, может они шутили, но я занялся и вот что получилось.

// MSV Lib. Tuple. 2011.04.01 21:60

#define TPLM Tuple(TPLMOVE) + 
#define TPLC Tuple(TPLCOPY) + 
#define TPL Tuple() + 
//#define GTPL Tuple() +
#define TPLERROR(t) { memcpy(0, 0, 1); }

#define TPLMOVE    1 // copy to tuple, memset 0 original. = destruct dest, copy to dest.
#define TPLCOPY    2 // copy constructor = destruct dest, copy to dest
#define TPLGET    3 // destruct all values :)

#include <memory.h>
#include <math.h>
#include <stdio.h>
#include <typeinfo>
#include <string.h>

#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))

unsigned int mcrc(char* name, unsigned int sz){
    unsigned int ret=0; if(!sz) sz=(unsigned int)strlen(name);
    char*t=name+sz; int p=0;
    while(name<t){
        *(((char*)&ret)+p)+=*name; p++;
        if(p>=4) p=0; name++;
    }
return ret;
}

struct Tupled{ unsigned int sz, type; void *v; char data[0]; };

class Tuple{
    int count, set, dusz, dasz;
    unsigned char *data;
    int type; int adel; 

public:
    Tuple(){ count=0; set=0; type=0; dusz=0; dasz=0; data=0; adel=0; }
    Tuple(int t){ type=t; }

    ~Tuple(){ if(count!=set) TPLERROR("~Tuple"); delete data; }

    Tuple(Tuple &t){
        count=t.count; set=t.set; dusz=t.dusz; dasz=t.dasz; data=t.data;
        t.count=0; t.set=0; t.data=0; adel=1;
    }

    template <class T>
    Tuple& operator+(T &t){ if(!adel) Add(&t, sizeof(t), t); else Del(&t, sizeof(t), t); return *this; }
    template <class T>
    Tuple& operator-(T &t){ if(!adel) Add(&t, sizeof(t), t); else Del(&t, sizeof(t), t); return *this; }
    template <class T>
    Tuple& operator*(T &t){ if(!adel) Add(&t, sizeof(t), t); else Del(&t, sizeof(t), t); return *this; }
    template <class T>
    Tuple& operator/(T &t){ if(!adel) Add(&t, sizeof(t), t); else Del(&t, sizeof(t), t); return *this; }
    template <class T>
    Tuple& operator,(T &t){ if(!adel) Add(&t, sizeof(t), t); else Del(&t, sizeof(t), t); return *this; }
    template <class T>
    Tuple& operator>(T &t){ if(!adel) Add(&t, sizeof(t), t); else Del(&t, sizeof(t), t); return *this; }
    template <class T>
    Tuple& operator <(T &t){ if(!adel) Add(&t, sizeof(t), t); else Del(&t, sizeof(t), t); return *this; }

    template <class T>
    void Add(void *v, int s, T &t){
        if(dasz-dusz<s+4+(int)sizeof(void*)){
            unsigned char *ldata=data;
            data=new unsigned char[dasz+max(128, s+4)];
            memcpy(data, ldata, dasz);
            dasz+=max(128, s);                    
            delete [] ldata;
        }
        Tupled &d=*(Tupled*)(data+dusz);
        d.sz=s;
        memcpy(&d.v, v, sizeof(void*));
        if(type==TPLCOPY){ *(T*)d.data=t; } else memcpy(d.data, v, s);
        if(type==TPLMOVE) t.~T();

        d.type=mcrc((char*)typeid(t).name(), 0);
        dusz+=sizeof(Tupled)+s; count++;
    }

    template <class T>
    void Del(void *v, int s, T &t){
        if(set>=count){ TPLERROR("Tuple::Set"); return ; }
        unsigned char *p=GetData(set);
        if(!p){ TPLERROR("Tuple::NoData"); return ; }

        Tupled &d=*(Tupled*)p;
        unsigned int tp=mcrc((char*)typeid(t).name(), 0);
        if(tp!=d.type){ TPLERROR("Tuple::TYPE"); return ;}

        t.~T();
        if(d.sz!=s){ TPLERROR("Tuple::SIZE"); return ;}
        memcpy(v, d.data, d.sz);
        
        set++;
    }

    unsigned char* GetData(int c){
        if(c>=count) return 0;
        unsigned char *p=data;
        for(int i=0; i<c; i++){
            p+=sizeof(Tupled)+*(int*)p;
        }
        return p;
    }
};

Tuple T(){ int i=1, j=2, k=3; return TPL i, j, k; }
int T2(Tuple t){
    int a, b, c;
    t, a, b, c;
    printf(" T2: %d %d %d", a, b, c);
    return 1;
}

int main(){
    int a, b, c;
    T(), a, b, c;
    printf("%d %d %d", a, b, c);
    T2(TPL a + b + c);
    return 0;
}


Код можно скачать здесь:
http://source.centerix.ru/source/msv/Tuples/Tuples.cpp
ftp://source:source@source.centerix.ru/source/msv/Tuples/Tuples.cpp


Простенько и со вкусом. Без кучи шаблонов. Так как я видел это в D.
Создать Typle не проблема, сложнее оказалось сделать их использование достаточно простым.
В итоге получилось сделать даже проще, чем я мог предполагать. Хватило одного класса.
В принципе, переменные в списке можно разделять любым знаком TPL a , b + c — d * e / f < g > h; но думаю лучше оставить одну запятую, хотя практика показывает, что этого мало.
Единственный минус, это переменные после вызова функции: T(), a, b... К сожалению перед функцией так и не получилось сделать. при использовании +-*/<> переменные выполняли эти операции раньше. При разделении запятыми переменные вообще исчезали. В общем, против направления выполнения не попрешь.

Контроль за количеством переменных и типами оставляю на программиста, если он ошибется вызывается memcpy(0, 0, 1); мне показалось это достаточно прямолинейное сообщение об ошибке. Можно сделать что-нибудь попроще.

Таким же способом можно передавать туплы в функции. Запятые не прошли, пришлось использовать знаки +.

Хотелось бы узнать, есть ли еще реализации туплов. Про туплы на boost слышал. Мне не понравилось. Там каждый шаг нужно описывать.
Хотелось бы узнать, есть ли желающие использовать мою разработку. Я не знаю, буду ли использовать ее, или более привычное получение результатов через адреса int &i. Я обычно стремлюсь к оптимизации, int &i быстрее. Хотя тут действительно небольшие потери в скорости.

Разработка еще не закончена. Есть еще пара идей по ускорению. Если будут пожелание по расширению функционала, можно рассмотреть.
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re: Tuple для C++. Хотим оценок.
От: minorlogic Украина  
Дата: 04.04.11 05:16
Оценка:
Не забывайте что в бусте несколько реализаций тюплов.

boost::fusion::
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: Tuple для C++. Хотим оценок.
От: night beast СССР  
Дата: 04.04.11 05:57
Оценка:
Здравствуйте, MikelSV, Вы писали:

MSV>Дата: 02.04.11 13:34

MSV>Вчера совершенно случайно начали обсуждать tuple и их реализацию в С++, может они шутили, но я занялся и вот что получилось.

MSV>
MSV>struct Tupled{ unsigned int sz, type; void *v; char data[0];};
MSV>


она вобще компилируется?
выравнивение учитывает?

MSV>Контроль за количеством переменных и типами оставляю на программиста, если он ошибется вызывается memcpy(0, 0, 1); мне показалось это достаточно прямолинейное сообщение об ошибке. Можно сделать что-нибудь попроще.


assert?

MSV>Таким же способом можно передавать туплы в функции. Запятые не прошли, пришлось использовать знаки +.


make_tuple(...)?

MSV>Хотелось бы узнать, есть ли еще реализации туплов. Про туплы на boost слышал. Мне не понравилось. Там каждый шаг нужно описывать.


std::tuple
Re[2]: Tuple для C++. Хотим оценок.
От: MikelSV http://www.centerix.ru
Дата: 04.04.11 06:26
Оценка:
Здравствуйте, night beast, Вы писали:

MSV>>
MSV>>struct Tupled{ unsigned int sz, type; void *v; char data[0];};
MSV>>


NB>она вобще компилируется?

NB>выравнивение учитывает?

Оказывается мноие удивляются char data[0];. Я с этим давно работаю, оно нормально компилируется и не занимает размера в структуре, а обращаться можно. Это неплохо используется, когда нужно разместить в памяти несколько структур содержащих текстовые данные неизвестной заранее длинны.
Это уже не привычные массивы, где элементы расставлены через четкие расстояния, здесь все определяется размером в unsigned int sz.
Компилятор на это выдает предупреждение, но работает без проблем.

NB>assert?

Да, assert(0); вполне подходит.

MSV>>Таким же способом можно передавать туплы в функции. Запятые не прошли, пришлось использовать знаки +.

NB>make_tuple(...)?
Я старался уйти от вызова функций. Так же для каждого количества переменных в тупле нужно писать свою функцию. В принципе, вызов функции будет работать быстрее, так как сразу известны все переменные. В принципе make_tuple() без проблем реализуется в моем коде.

NB>std::tuple

Почитаю.
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re: А зачем он на практике?
От: Temnikov Россия  
Дата: 04.04.11 06:33
Оценка:
В описании boost почитал описание Tuple, но так и не понял зачем на практике он?
Re: Tuple для C++. Хотим оценок.
От: Sni4ok  
Дата: 04.04.11 06:36
Оценка: -1 :)
Здравствуйте, MikelSV, Вы писали:

MSV>Основной аргумент против этого кода: он не нужен, есть boost::tuple.


MSV>Простенько и со вкусом.


разве что со вкусом говна, к примеру у boost::tuple можно узнать размер на этапе компиляции с помощью boost::fusion::result_of::size, а ещё он нормально работает с полиморфными обьектами.
Re: Tuple для C++. Хотим оценок.
От: rg45 СССР  
Дата: 04.04.11 06:42
Оценка: :))) :)
Здравствуйте, MikelSV, Вы писали:

MSV>Это перепост темы, по просьбам трудящихся, из форума исходники. За два дня на нее не было ни одного ответа, которых так хотелось. В следствии чего была высказана мысль написать еще раз в форум c++.


С уваженьем (Дата, Подпись)
Отвечайте нам, а то
Если вы не отзоветесь,
Мы напишем в "Спортлото"


--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Tuple для C++. Хотим оценок.
От: LaptevVV Россия  
Дата: 04.04.11 06:52
Оценка:
Здравствуйте, night beast, Вы писали:
MSV>>Вчера совершенно случайно начали обсуждать tuple и их реализацию в С++, может они шутили, но я занялся и вот что получилось.

MSV>>
MSV>>struct Tupled{ unsigned int sz, type; void *v; char data[0];};
MSV>>


NB>она вобще компилируется?

NB>выравнивение учитывает?
Кажись у Герба Саттера было описано про нулевой размер массива.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Tuple для C++. Хотим оценок.
От: uzhas Ниоткуда  
Дата: 04.04.11 06:52
Оценка: 5 (1)
Здравствуйте, MikelSV, Вы писали:

MSV>Два основных вопроса: нужен ли данный код и можно ли его использовать в реальных задачах?

его можно использовать в крайне узкоспециализированных задачах, на роль generic он не годится
1) он банально не скомпилируется, код некорректен с точки зрения стандарта
2) алгоритм, опирающийся на typeid::name непереносим, ибо никаких требований стандарт не возлагает на эти строки (к примеру, они все могут быть пустыми)
3) нет самых необходимых операторов — копирование и сравнивание (operator==)
4) проблемы с доступом к невыровненным данным
5) далеко не все сущности можно хранить через memcpy, так что набор поддерживаемых типов крайне ограничен

MSV>Контроль за количеством переменных и типами оставляю на программиста

это один из серьезнейших недостатков и его решают обычно обилием шаблонов
также было бы интересно, как клиенту класть значения в тупл и доставать. приведите, пожалуйста, код
я рекомендую вам проверить код на codepad.org прежде, чем выкладывать его
Re[2]: Tuple для C++. Хотим оценок.
От: MikelSV http://www.centerix.ru
Дата: 04.04.11 07:53
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, MikelSV, Вы писали:


MSV>>Два основных вопроса: нужен ли данный код и можно ли его использовать в реальных задачах?

U>его можно использовать в крайне узкоспециализированных задачах, на роль generic он не годится
U>1) он банально не скомпилируется, код некорректен с точки зрения стандарта
U>2) алгоритм, опирающийся на typeid::name непереносим, ибо никаких требований стандарт не возлагает на эти строки (к примеру, они все могут быть пустыми)
U>3) нет самых необходимых операторов — копирование и сравнивание (operator==)
U>4) проблемы с доступом к невыровненным данным
U>5) далеко не все сущности можно хранить через memcpy, так что набор поддерживаемых типов крайне ограничен

MSV>>Контроль за количеством переменных и типами оставляю на программиста

U>это один из серьезнейших недостатков и его решают обычно обилием шаблонов
U>также было бы интересно, как клиенту класть значения в тупл и доставать. приведите, пожалуйста, код
U>я рекомендую вам проверить код на codepad.org прежде, чем выкладывать его

Код компилируется, в MSVS и g++, и мне кажется стандарт не против. на codepad.org он работать не захотел, похоже там стоит флаг считать все предупреждения ошибками. удалил char data[0]; заменил все d.data на (&d+1). предупреждение пропало. codepad.org нашел что-то еще. Там походу другой компилятор, надо поставить себе, разобраться, что он хочет.

Есть в стандарте способ получить уникальный идентификатор типа? может ссылка на структуру, или id? По идее что-то должно быть, переносимое, но я к сожалению не в курсе и знаю только про typeid.

Оператор копирования есть, но работает он достаточно интересным способом. Когда Tuple передается из/в функцию, вызывается оператор копирования и Tuple начинает вставлять данные в переменные. Вставка данных: Tuple(), a, b, c; Передача в функцию: Tuple(Tuple&t), установка флага вставки данных. Вставка данных в переменные: t, i, j, k; Боюсь это цена за мою реализацию без функций make_tuple() и прочих.

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

Я слегка не разобрался, как лучше работать с данными. Есть три варианта: memcpy, перемещение и копирование. Это заложено в define TPLM — move и TPLC — copy. Полагаю более правильный вариант копировать данные, перемещение было бы быстрее( memcpy и memset(0); ), но есть шанс задеть глобальные данные.

Данные кладутся через: Tuple t; t + i; t + k + j; Для извлечения можно сделать функцию. void Out(){ adel=1; } Если Tuple передан в/из функции, будет вызван оператор копирования Tuple(Tuple&t) и флаг установится автоматически. Данные извлекаются так же: t + i; t + k + j;

--
Данный код адаптирован под задачи, которые я смог увидеть: Передача нескольких переменных из/в функцию. Я не очень представляю, какие операции понадобится выполнять с туплами. Я приложил все усилия, чтобы оптимизировать их именно под эти задачи. Я хотел исключить все явные вызовы функций, и кажется мне это удалось. Написать функции не проблема, полагаю даже нужно, они будут проще для понимания

Я вижу, что этот код еще в самом начале своего развития, есть множество задач под которые он не рассчитывался и не писалась реализация функционала.
Я бы хотел продолжить его разрабатывать, но мне нужны задачи, которые, надеюсь, предоставят те, кто использует туплы. Я бы хотел узнать о бо всех областях, в которых их можно применить.

Я постараюсь придерживаться своего варианта по мере возможностей, но уже вижу, что еще сильнее скачусь в шаблоны. Но все же надеюсь оставить такое же простое использование при решении простейших задач.
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re[3]: Tuple для C++. Хотим оценок.
От: night beast СССР  
Дата: 04.04.11 08:32
Оценка:
Здравствуйте, MikelSV, Вы писали:

MSV>Здравствуйте, night beast, Вы писали:


MSV>>>
MSV>>>struct Tupled{ unsigned int sz, type; void *v; char data[0];};
MSV>>>


NB>>она вобще компилируется?


MSV>Оказывается мноие удивляются char data[0];. Я с этим давно работаю, оно нормально компилируется и не занимает размера в структуре, а обращаться можно. Это неплохо используется, когда нужно разместить в памяти несколько структур содержащих текстовые данные неизвестной заранее длинны.

MSV>Это уже не привычные массивы, где элементы расставлены через четкие расстояния, здесь все определяется размером в unsigned int sz.
MSV>Компилятор на это выдает предупреждение, но работает без проблем.

в Си для этого использовали char data[];
в Си++ массив нулевого размера -- распространенная методика получения ошибки времени компиляции.

MSV>>>Таким же способом можно передавать туплы в функции. Запятые не прошли, пришлось использовать знаки +.

NB>>make_tuple(...)?
MSV>Я старался уйти от вызова функций. Так же для каждого количества переменных в тупле нужно писать свою функцию. В принципе, вызов функции будет работать быстрее, так как сразу известны все переменные. В принципе make_tuple() без проблем реализуется в моем коде.

__VA_ARGS__?
Re[4]: Tuple для C++. Хотим оценок.
От: MikelSV http://www.centerix.ru
Дата: 04.04.11 08:50
Оценка:
Здравствуйте, night beast, Вы писали:

NB>в Си для этого использовали char data[];

NB>в Си++ массив нулевого размера -- распространенная методика получения ошибки времени компиляции.

Реакция на char data[]; такая же как и на char data[0]; — Студия пишет ошибку, g++ молчит.

NB>__VA_ARGS__?

Не очень понятно, причем здесь это. не вижу, как оно может быть использовано.
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re[5]: Tuple для C++. Хотим оценок.
От: night beast СССР  
Дата: 04.04.11 08:58
Оценка:
Здравствуйте, MikelSV, Вы писали:

NB>>в Си для этого использовали char data[];

NB>>в Си++ массив нулевого размера -- распространенная методика получения ошибки времени компиляции.
MSV>Реакция на char data[]; такая же как и на char data[0]; — Студия пишет ошибку, g++ молчит.

как получить в С++ такого же эффекта я не знаю (на самом деле оно в нем и не нужно)

NB>>__VA_ARGS__?

MSV>Не очень понятно, причем здесь это. не вижу, как оно может быть использовано.

вы и есть за меня будете?
ага


не вижу, чем (TPL a + b + c) принципиально лучше чем MAKE_TPL(a,b,c)
#define MAKE_TPL(...) ( Tuple(),__VA_ARGS__ )


PS: TPL 5 работает? а на g++?
Re: Хотите оценок?
От: gegMOPO4  
Дата: 04.04.11 09:06
Оценка: 1 (1) +1 -2
http://govnokod.ru/6191
Re[2]: Хотите оценок?
От: night beast СССР  
Дата: 04.04.11 09:15
Оценка: +3
Здравствуйте, gegMOPO4, Вы писали:

MOP>http://govnokod.ru/6191


зря ты так. ну тренируется человек, кому от этого плохо?
Re[6]: Tuple для C++. Хотим оценок.
От: jyuyjiyuijyu  
Дата: 04.04.11 09:16
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, MikelSV, Вы писали:


NB>>>в Си для этого использовали char data[];

NB>>>в Си++ массив нулевого размера -- распространенная методика получения ошибки времени компиляции.
MSV>>Реакция на char data[]; такая же как и на char data[0]; — Студия пишет ошибку, g++ молчит.

NB>как получить в С++ такого же эффекта я не знаю (на самом деле оно в нем и не нужно)


студия (msvc2008) нормально компилит
и в Си и в Си++ режиме
такой код
struct ___
{
    int _;
    char __[];
};
Re[3]: Хотите оценок?
От: Sni4ok  
Дата: 04.04.11 09:19
Оценка:
Здравствуйте, night beast, Вы писали:

NB>зря ты так. ну тренируется человек, кому от этого плохо?


человек же сам попросил оценок, тоесть он готов и хочет критику.
Re[7]: Tuple для C++. Хотим оценок.
От: night beast СССР  
Дата: 04.04.11 09:20
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

NB>>как получить в С++ такого же эффекта я не знаю (на самом деле оно в нем и не нужно)


J>студия (msvc2008) нормально компилит

J>и в Си и в Си++ режиме
J>такой код
J>
J>struct ___
J>{
J>    int _;
J>    char __[];
J>};
J>


гсс 3.4.2 отказывается.
Re[6]: Tuple для C++. Хотим оценок.
От: MikelSV http://www.centerix.ru
Дата: 04.04.11 09:21
Оценка: :)
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, MikelSV, Вы писали:


NB>не вижу, чем (TPL a + b + c) принципиально лучше чем MAKE_TPL(a,b,c)

NB>
NB>#define MAKE_TPL(...) ( Tuple(),__VA_ARGS__ )
NB>


NB>PS: TPL 5 работает? а на g++?


Да, не подумал. На g++ тоже работает.
Я недолюбливаю __VA_ARGS__ за то, что они не работают в 2003 студии.
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re[4]: Хотите оценок?
От: night beast СССР  
Дата: 04.04.11 09:33
Оценка: 2 (2) +1
Здравствуйте, Sni4ok, Вы писали:

NB>>зря ты так. ну тренируется человек, кому от этого плохо?


S>человек же сам попросил оценок, тоесть он готов и хочет критику.


критика, это не "ваш код г*но", а "ваш код г*но, потому что ..."
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.