views:

76

answers:

3

that's the code:

static inline void 
shrinkData(const vector<Data> &data, unsigned short shrinkType){
    #define CASE_N(N) \
    case(N): \
        ptr = MemoryManager::requestMemory(n*sizeof(ShrinkData<N>)); \
        for(int i=0; i<n; i++){ \
            new(ptr) ShrinkData<N>(data[i]); \
            ptr+=sizeof(ShrinkData<N>); \
        } \
        return;


    int n = data.size();
    char* ptr;

    switch(shrinkType){
    case(0):
        return;
    CASE_N(1)
    CASE_N(2)
    CASE_N(3)
    ....
    CASE_N(255)
}

now I get a fatal "error C1061: compiler limit : blocks nested too deeply" on line CASE_N(124)

can someone please tell me why this happens? actually the nesting should not be deeper than 2, no?

Thanks!

//edit: the requested constructor (the constructor works just fine without this switch function)

enum {//maximally 16 to fit in a unsigned short!
    EID_POSITION        =   1, //bit1
    EID_T               =   2, //bit2
    EID_GEOMNORMAL      =   4, //bit3
    EID_NORMAL          =   8, //bit4
    EID_TANGENTS        =  16, //bit5
    EID_TEXCOORDS       =  32, //bit6
    EID_RAYDIR          =  64, //bit7
    EID_RECURSIONDEPTH  = 128  //bit8
};



template<unsigned, unsigned>
struct IDataMember{
    IDataMember(){}
    IDataMember(const Data &iData){}
};


template<>
struct IDataMember<EID_POSITION, EID_POSITION>{
    IDataMember(): position(Vector3(0,0,0)){}
    IDataMember(const Data &iData):position(iData.position){}
    Vector3 position;
};

... the same kind of template specialisation for each type in the enums...

template<unsigned members>
struct ShrinkData
    :public IDataMember<members & EID_POSITION, EID_POSITION>
    ,public IDataMember<members & EID_T, EID_T>
    ,public IDataMember<members & EID_GEOMNORMAL, EID_GEOMNORMAL>
    ,public IDataMember<members & EID_NORMAL, EID_NORMAL>
    ,public IDataMember<members & EID_TANGENTS, EID_TANGENTS>
    ,public IDataMember<members & EID_TEXCOORDS, EID_TEXCOORDS>
    ,public IDataMember<members & EID_RAYDIR, EID_RAYDIR>
    ,public IDataMember<members & EID_RECURSIONDEPTH, EID_RECURSIONDEPTH>
{
    ShrinkData()
        :IDataMember<members & EID_POSITION, EID_POSITION>()
        ,IDataMember<members & EID_T, EID_T>()
        ,IDataMember<members & EID_GEOMNORMAL, EID_GEOMNORMAL>()
        ,IDataMember<members & EID_NORMAL, EID_NORMAL>()
        ,IDataMember<members & EID_TANGENTS, EID_TANGENTS>()
        ,IDataMember<members & EID_TEXCOORDS, EID_TEXCOORDS>()
        ,IDataMember<members & EID_RAYDIR, EID_RAYDIR>()
        ,IDataMember<members & EID_RECURSIONDEPTH, EID_RECURSIONDEPTH>(){}


    ShrinkData(const Data &iData)
        :IDataMember<members & EID_POSITION, EID_POSITION>(iData)
        ,IDataMember<members & EID_T, EID_T>(iData)
        ,IDataMember<members & EID_GEOMNORMAL, EID_GEOMNORMAL>(iData)
        ,IDataMember<members & EID_NORMAL, EID_NORMAL>(iData)
        ,IDataMember<members & EID_TANGENTS, EID_TANGENTS>(iData)
        ,IDataMember<members & EID_TEXCOORDS, EID_TEXCOORDS>(iData)
        ,IDataMember<members & EID_RAYDIR, EID_RAYDIR>(iData)
        ,IDataMember<members & EID_RECURSIONDEPTH, EID_RECURSIONDEPTH>(iData){}

};
A: 

Just speculating, but the function is tagged inline and it uses templates as well, maybe that's part of where the extra nesting is coming from.

However, more likely IMO, the resource limit you're hitting probably isn't in actuality so clear cut as "levels of nesting" but rather that is the perceived most common cause of hitting it so that's what the error message refers to.

Logan Capaldo
+2  A: 

I suppose that error message is bogus. There likely really is a compiler limit, but it's unlikely the block nesting.

Anyway, what happens if you put that code for each case into its own function template and just call that?
Also, inlining this function is very likely not gaining you anything, since it will request memory and execute a loop. Function call overhead must be neglectable compared to that. (No matter how few iterations that loop takes, just setting it up by itself is probably half as expensive as calling a function.)
Finally, I'd try to get rid of the macro, just in case.

The code might then look like this:

// Beware, brain-compiled code ahead!
template<unsigned short N>
void do_it(int n)
{
  char* ptr = MemoryManager::requestMemory(n*sizeof(ShrinkData<N>));
  for(int i=0; i<n; i++){
    new(ptr) ShrinkData<N>(data[i]);
    ptr+=sizeof(ShrinkData<N>);
  }
}

static void 
shrinkData(const vector<Data> &data, unsigned short shrinkType)
{
  const std::vector<Data>::size_type n = data.size();
  switch(shrinkType){
    case   0: break
    case   1: do_it<  1>(n); break;
    case   2: do_it<  2>(n); break;
    .
    .
    .
    case 254: do_it<254>(n); break;
    case 255: do_it<255>(n); break;
}
sbi
+1  A: 

According to this link there is a "feature" in compiler that allows only for limited number of loops. Never happened to me. Try to put ptr initialization and the following for loop in a block. Another solution is to create template function that covers the whole snippet, so that the macro becomes something like this:

#define CASE_N(N) \
case(N): \
    ptr = requestAndInitialize<N>(data); \
    return;
Dialecticus
hey that really did do the trick! putting everything after the "case(N):" into a block made it compile just fine! Anyone an idea what's the difference???
Mat
I guess that compiler tracks consecutive loops for some purpose (for optimization maybe). Loops in separate blocks are not consecutive. Not in the same scope.
Dialecticus
@Mat: If you hover your mouse over the up-vote button, you will see a messages saying "This answer is useful". And that's exactly what this button is for: you click it when you think an answer is useful. It just escapes me how someone would celebrate a good answer without also up-voting it...
sbi
@sbi: To be fair he did accepted it as the best answer. I won't complain about 10 more points, though.
Dialecticus
I can't click it I don't have an account. but I apreciate your help nevertheless :)
Mat