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 быстрее. Хотя тут действительно небольшие потери в скорости.

Разработка еще не закончена. Есть еще пара идей по ускорению. Если будут пожелание по расширению функционала, можно рассмотреть.
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.