このプロジェクトでは、1つの巨大なアレイを作成する必要があります(最大7.13e + 17のアレイを作成できるといいのですが、このターゲットはまだ先にあります)。
これは、大規模な割り当てを回避するために、キーがインデックスであるデジタルツリー(またはbツリー)という専用の構造を作成することを要求します。
大規模な割り当て、特に再割り当ては、不要なメモリの断片化を引き起こす可能性があります。大きな配列を小さなチャンクに分割すると、配列の拡張が容易になるだけでなく、疎な配列の表示も可能になります。
NB~7.13e+17
は約60ビットの長さです。それだけのRAMをサポートできるハードウェアもありますか?業界をしっかりとフォローしているわけではありませんが、58ビットのアドレスバスを備えたNUMAアーチについて簡単に聞きましたが、60ビット以上のアーチについては何も聞きませんでした。
配列内の各セルには、0、1、2.2の3つの値のいずれかを含めることができます。
セルに含まれる値が3つだけの場合(2.2は2として表すことができます)、2ビットの情報になります。uint32_t
つまり、 16個の値とuint64_t
32個の値にパックできるということです。
既存のデジタルツリーの実装を見つけて(または独自にロールして)、インデックスの主要な上位ビットとして使用することができます。元のインデックスの残りのビットは、値がパックされた配列であるツリーリーフへのインデックスになります。std::map
トライの代わりに使用する例として、テストされていません。
enum {
LS_BITS = 16,
MS_BITS = 64-LS_BITS
};
enum {
VALUE_BITS = 2,
VALUE_MASK = ((1<<VALUE_BITS)-1)
};
// this represents an array of `1<<LS_BITS` values
struct leaf_node {
uint64_t packed_data[ ((1<<LS_BITS)*VALUE_BITS) / (sizeof(uint64_t)*8) ];
};
// that should be a trie, to provide faster look-up
typedef std::map< uint64_t, leaf_node > big_array_type;
void
big_array_set_value( big_array_type &b, uint64_t index, uint64_t value )
{
leaf_node &n = b[index >> LS_BITS];
uint64_t li = index & ((1<<LS_BITS)-1);
li *= VALUE_BITS; // convert into bit offset
uint64_t &x = n.packed_data[ li / (sizeof(uint64_t)*8) ];
li %= (sizeof(uint64_t)*8);
x = (x & (VALUE_MASK<<li)) | (value << li);
}
int
big_array_get_value( big_array_type &b, uint64_t index, uint64_t value )
{
leaf_node &n = b[index >> LS_BITS];
uint64_t li = index & ((1<<LS_BITS)-1);
li *= VALUE_BITS; // convert into bit offset
uint64_t &x = n.packed_data[ li / (sizeof(uint64_t)*8) ];
li %= (sizeof(uint64_t)*8);
return (x >> li) & VALUE_MASK;
}
この方法では、ストレージが2ビットで4つの値を使用できるため、0.5ビットの情報が無駄になりますが、使用されるのは3つだけです。これも改善できますが、アクセスパフォーマンスのコストがはるかに高くなります。