Re[12]: расмоложение мемберов класса в памяти
От: Erop Россия  
Дата: 16.06.10 08:30
Оценка: 3 (1)
Здравствуйте, szag, Вы писали:

S>
S>#define FIELD(TypeID, RealType, name, captionID, ...)            \
S>class RealType ## _ ## name : public ORMfield<TypeID, RealType>      \
S>{                                                                    \
S>public:                                                              \
S>    explicit RealType ## _ ## name () : ORMfield(#name , captionID)  \
S>    {                                                                \
S>        InitValue(FieldValue);                                       \
S>    }                                                                \
S>                                                                     \
S>   // куча кода опущена                                                                  \
S>                                                                     \
S>    std::size_t GetSize() const                                      \
S>    {                                                                \
S>        return sizeof( RealType ## _ ## name ) +                     \
S>            MyAlign<RealType ## _ ## name>::Result;                  \
S>    }                                                                \
S>                                                                     \
S>    __VA_ARGS__                                                      \
S>                                                                     \
S>};                                                                   \
S>                                                                     \
S>RealType ## _ ## name name;
S>


Вот! Наконец-то попёрла конкретика!
Только всё равно не понятно, что такое TypeID и зачем он нужен.
Ещё не совсем мне понятно, зачем нужно чтобы на каждое поле был свой класс? Из-за инициализатора только?
IMHO, можно так не делать, а инициализаторы передавать в конструкторе таблицы.

Но я не про это.
Во-первых, даже с классом на каждое поле, конструкцию можно упростить.

Типа написать шаблон
template<typename MDT, typename TypeID, typename TRealType> 
class ORMfield {
//  тут всё так, как у тебя и есть +
    std::size_t GetSize() const;
    {                                                                \
        return sizeof( RealType ## _ ## name ) +                     \
            MyAlign<RealType ## _ ## name>::Result;                  \
    }                                                                \
 
};
template<typename MDT, typename TypeID, typename TRealType>
std::size_t GetSize();
{                                                                
    return sizeof( MDT ) + MyAlign<MDT>::Result;                 
}


Во-вторых, на сколько я понял, место тебе не жаль?
Тогда можно сдать так, что все ORMfield будут выравниваться одинаково. На что-то одно и то же, достаточно большое.
Ну, например, иметь такой вот простенький шаблон:
template<typename T, typename TAlignAs = double> class AlignedData {
    union {
        TAlignAs dummy;
        char buffer[sizeof( T )];
    } data;
public:
    AlignedData() { new( data.buffer ) T; }
    AlignedData( const AlignedData& other ) { new( data.buffer ) T( other.Get() ); }
    template<typename T1>
    AlignedData( T1 t1 )  { new( data.buffer ) T( t1 ); }
    template<typename T1, typename T2>
    AlignedData( T1 t1, T2 t2 )  { new( data.buffer ) T( t1, t2 ); }
    ~AlignedData() { Get().~T(); }

    void operator = ( const AlignedData& other ) { Get() = other.Get(); }

    T& Get() { return *static_cast<T*>( data.buffer ); }
    const T& Get() const { return *static_cast<const T*>( data.buffer ); }
};


И внутри ORMfield хранить все данные в виде AlignedData<RealType>
Тогда на GetSize можно будет просто забить, а сделать у всех ORMfield общую базу, типа ORMfieldBase и заиметь у неё метод virtual const ORMfieldBase* GetNext() const...


S>fields представляет из себя поток дефайнов, вида:
S>
S>INT(id, 50, INITVALUE(100))
S>STRING(name, 100, 60, INITVALUE(L"TestDefaultString"))
S>DATE(birthday, 10)
S>TIME(localtime, 31)
S>BOOL(IsOk, 25)
S>DOUBLE(pisun, 45)
S>


Что касается той идеи, что предлагал КодТ, то там всё просто.

Я напишу так, словно у тебя есть только тип int и немного на псевдокоде, а ты обобщишь потом на всё, что тебе надо.
Пишешь, такую систему макросов:
#define EXTRACT_FIELDS_END_OF_LIST_
#define EXTRACT_FIELDS_INT( NAME, TYPE_ID, INIT_VALUE ) \
    /* тут собственно кусок твоего старого определение INT */ FIELD( int, NAME, TYPE_ID, INIT_VALUE )\
    EXTRACT_FIELDS_##
EXTRACT_FIELDS( FIELDS ) EXTRACT_FIELDS_##FIELDS END_OF_LIST_ 
// Тут, на самом деле, надо немного схимичить, чтобы FIELDS подставилось раньше, чем развернётся, но я пока не буду


Потом пишешь ещё макросы EXTRACT_INITIALIZATORS_LIST, EXTRACT_TABLE_OF_OFFSETS и т. д. и живёшь себе счастливо без виртуальных функций GetSize

Да, по поводу "схимичить" всё уже схимичено в бусте. Если ты не можешь его заюзать, а IMHO, это жёсткое требованиек клиентам -- доставить буст. Ты можешь выдрать химию оттуда, или попроси, тебе тут помогут.

Вот.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: расмоложение мемберов класса в памяти
От: Кодт Россия  
Дата: 16.06.10 15:18
Оценка: 3 (1)
К>Завтра попробую на BOOST/PP родить рабочий пример.

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/facilities/expand.hpp>
#include <boost/preprocessor/punctuation/paren.hpp>
#include <boost/preprocessor/tuple/elem.hpp>

// T_xxx - макросы для внутреннего использования

// генератор структуры
#define TABLE(name,meta,fields) \
    struct name : ORMTableBase { \
        meta \
        BOOST_PP_SEQ_FOR_EACH(T_APPLY, (T_MEMBER,name), fields) \
        static const FieldInfo* reflection() { \
            static const FieldInfo refs[] = { \
                BOOST_PP_SEQ_FOR_EACH(T_APPLY, (T_REFLECTION,name), fields) \
                {} \
            }; \
            return refs; \
        } \
    }; \
    //ENDMACRO

// колбеки - генераторы элементов
#define T_MEMBER(name,type,var,...) type var;
#define T_REFLECTION(name,type,var,...) { BOOST_PP_STRINGIZE(var), sizeof(type), _offsetof(name,var) },

// T_APPLY - общий колбек (высшего порядка!) для макроса FOR_EACH
// принимает 3 параметра (r,data,elem)
// r - номер следующего элемента, - т.е. 2, 3, 4, и т.д. - бустовские штучки
// data - общий параметр, у нас это (T_MEMBER,name) или (T_REFLECTION,name) - т.е. колбек + имя класса
// elem - элемент серии, т.е. информация об очередном поле (type,var,etc...)

// T_APPLY(r,(macro,name),(type,var,etc...)) --> T_APPLY_( macro, name, type,var,etc... ) -- последняя пачка идёт одним аргументом!
#define T_APPLY(r,mn,fld) \
    BOOST_PP_EXPAND( \
        T_APPLY_(BOOST_PP_TUPLE_ELEM(2,0,mn), BOOST_PP_TUPLE_ELEM(2,1,mn), T_UNWRAP fld) \
    ) \
    //ENDMACRO
#define T_APPLY_(macro,name,fld) macro BOOST_PP_LPAREN() name,fld ) // --> macro ( name , type,var,etc... )

#define T_UNWRAP(...) __VA_ARGS__ // (x,y,z,t) --> x,y,z,t


// тестируем...
TABLE(foo, hello, ((int,x)) ((char,y)) )

// на выходе получилось
struct foo : ORMTableBase {
    hello
    int x;
    char y;
    static const FieldInfo* reflection() {
        static const FieldInfo refs[] = {
            { "x", sizeof(int), _offsetof(foo,x) },
            { "y", sizeof(char), _offsetof(foo,y) },
            {}
        };
        return refs;
    }
};
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.