#ifndef _GPD_XS_MAPPER_CONTEXT_INCLUDED
#define _GPD_XS_MAPPER_CONTEXT_INCLUDED
#include "EXTERN.h"
#include "perl.h"
#include "ppport.h"
#include "perl_unpollute.h"
#include <vector>
#include <list>
namespace gpd {
class MapperContext {
public:
enum Kind {
Array = 1,
Hash = 2,
Message = 3,
};
struct ArrayItem {
AV *array;
unsigned int index;
};
struct HashItem {
HV *hash;
SV *svkey;
const char *keybuf;
STRLEN keylen;
};
struct ExternalItem {
int kind;
unsigned int id;
union {
ArrayItem array_item;
HashItem hash_item;
};
ExternalItem(Kind _kind, unsigned int _id) :
kind(_kind), id(_id) {
}
};
struct Item : public ExternalItem {
unsigned int *nextId;
Item(Kind _kind, unsigned int _id, unsigned int *_nextId) :
ExternalItem(_kind, _id), nextId(_nextId) {
}
void set_hash_key(SV *key) {
hash_item.svkey = key;
id = (*nextId)++;
}
void set_hash_key(const char *buffer, STRLEN len) {
hash_item.keybuf = buffer;
hash_item.keylen = len;
id = (*nextId)++;
}
void set_hash_key(HE *entry) {
if (HeKLEN(entry) == HEf_SVKEY) {
set_hash_key(HeKEY_sv(entry));
} else {
set_hash_key(HeKEY(entry), HeKLEN(entry));
}
}
void set_array_index(int index) {
array_item.index = index;
id = (*nextId)++;
}
};
void clear();
Item &push_level(AV *array) {
Item &level = push_level(Array);
level.array_item.array = array;
return level;
}
Item &push_level(HV *hash, Kind kind) {
return push_hash_level(hash, kind);
}
Item &push_level(SV *transformed, Kind kind) {
return push_hash_level(NULL, kind);
}
void pop_level() { next_level--; }
void fill_context(const ExternalItem * const **items, int *size);
private:
Item &push_level(Kind kind);
Item &push_hash_level(HV *hash, Kind kind) {
Item &level = push_level(kind);
level.hash_item.hash = hash;
level.hash_item.svkey = NULL;
level.hash_item.keybuf = NULL;
return level;
}
typedef std::list<Item> LevelStorage;
unsigned int nextId;
LevelStorage level_storage;
LevelStorage::iterator next_level;
std::vector<ExternalItem*> levels;
};
}
#endif