| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 
 | template <typename C>
class ComponentHolder{
    /* on doit pouvoir représenter un "index invalide" 
     * en utilisant la valeur maximale représentable par un size_t, on est sur 
     * que l'index représenté ne pourra JAMAIS être atteint
     */
    constexpr size_t invalidIndex{std::numeric_limits<size_t>::max()};
public:
    /* un alias de type, plus facile pour la représentation des composants */
    using ComponentType = Component<C>;
    /* des alias de type sur les itérateur pour les composants */
    using iterator = typename std::vector<ComponentType>::iterator;
    usign const_iterator = typname std::vector<ComponentType>::const_iterator;
    /* On veut pouvoir
     * 1- ajouter un composant à une entité particulière (pour autant qu'il n'existe pas)
     * 2- supprimer le composant pour une entité particulière (pour autant qu'il existe)
     * 3- parcourir tous les composants qui existent, indépendamment de l'entité à laquelle ils sont assignés (en lecture et en écriture)
     * 4- pouvoir accéder (en lecture et en écriture) au composant spécifiquement assigné à une entité particulière (pour autant qu'il existe)
     * 5- éventuellement, on peux souhaiter savoir s'il existe un composant pour une entité particulière (quand on travaille sur un seul type de composant
     *    cela peut s'avérer "plus facile" que de commencer à travailler avec le "pass-key" dont j'ai parlé plus haut
     */
     ComponentHolder(){
        indexes_.resize(0xFFFF, invalidIndex); // je débute directement avec 65000 et quelques indexes, qui sont tous invalides ;)
        /* NOTA: Je pourrais aussi réserver de l'espace pour les composants.
         *       Mais, dans l'ensemble, la politique d'augmentation de capacité de std::vector
         *       nous permettra de n'avoir "pas trop à nous en faire" sur ce point
         */
    }
    /* "le plus simple" : les fonctions begin() et end() (en version constante et non constante) */
    iterator begin(){
        return components_.begin();
    }
    iterator end(){
        return components_.end();
    }
    const_iterator begin() const{
        return components_.begin();
    }
    const_iterator end() const{
        return components_.end();
    }
    /* ajouter un composant
     *
     * précondition : l'entité indiquée ne doit pas encore disposer du composant
     *
     * mode de fonctionnement : 
     * 1- j'ajoute le composant au premier tableau
     * 2- je met à jour l'index dans le deuxième tableau
     */
    void add(ComponentType const & comp){
        assert(indexes_.size() < comp.id && "id too hight");
        assert(indexes_[comp.id] == invalidIndex  && "entity already has such component");
        components_.push_back(comp);
        indexes_[comp.id]= components_.size()-1; // on est dans un système "premier index à 0"
    }
 
    /* supprimer un composant
     *
     * précondition : l'entité indiquée doit disposer du composant
     *
     * mode de fonctionnement : 
     * 1- je supprime le composant au premier tableau
     * 2- je met à jour l'index dans le deuxième tableau (en lui donnant la valeur invalidIndex)
     */
    void remove(size_t entity){
        assert(indexes_[comp.id] != invalidIndex  && "entity already has such component");
        /* une suppression peut s'effectuer en temps constant dans un tableau si on ne tiens "pas trop"
         * à garder les élément dans un ordre particulier.
         * 
         * Il suffit en effet d'inverser l'élément que l'on veut supprimer avec le dernier élément valide 
         * avant de mettre la taille du tableau à jour
         * 
         * mais, pour cela, on a besoin de l'index (dans le premier tableau) de l'élément à supprimer
         */
       auto index = indexOf(entity);
       auto lastValid = indexes_.size()-1;
       std::swap(components_[index], lastValid());
       components_.resize(lastValid); // le redimentionnement à une taille inférieure ne provoque pas 
                      //la réallocation de la mémoire du tableau
       /* on met l'index à jour */
       indexes[entity]= invalidIndex;
    }
    /* accéder (en lecture et en écriture) au composant spécifiquement assigné à une entité particulière
     *
     * précondition : l'entité indiquée ne doit pas encore disposer du composant
     */
    ComponentType & get(size_t entity ){
        assert(indexes_[entity] != invalidIndex && "Entity doesn't have such component");
        return components_[indexOf(entity)];
    }
    ComponentType const & get(size_t entity) const{
        return const_cast<ComponentHolder &>(this).get(entity);
    }
    /* savoir si un composant est associé à une entité particulière */
    bool exists(size_t entity) const{
        return indexOf(entity)!=invalidIndex;
    }
private:
    /* En interne, on doit pouvoir récupérer l'index (dans le premier tableau) d'une entité bien précise 
     * 
     * précondition : la taille de l'index doit être plus grande que l'identifiant de l'entité indiquée 
     */
    size_t indexOf(size_t entity) const{
        assert(indexes_.size() < comp.id && "id too hight");
        return indexes_[entity];
    }
    /* le tableau de composants */
    std::vector<ComponentType> components_;
    /* le tableau d'indexes */
    std::vector<size_t> indexes_;
}; |