Skip to content
This repository has been archived by the owner on Nov 26, 2024. It is now read-only.

LSW::v4::SuperMap

Ernesto Luis (aka Lohkdesgds Lhuminury) edited this page Mar 11, 2020 · 11 revisions

LSW::v4::SuperMap


  • Arquivo: "Templates/templates.h"
  • Tipo: semi-dependente
    • Abort

O que é?


SuperMap é um std::map customizado que permite diferentes keys (tipos diferentes) para o mesmo valor. Assim como std::map, SuperMap tem seus "pairs", os SuperPair, responsáveis por essa parte de valor e keys. Ao contrário da biblioteca std, SuperPair permite os vários "tipos" de key. Vale constar que ele não diferencia const char* de um char* ou char[].


Como funciona?


SuperPair é bem simples, levemente diferente, mas semelhante ao std::pair. Cada SuperPair lida com um valor que você queira salvar, do tipo base do seu respectivo SuperMap (se houver). A forma mais direta de inicializar ele é com uma sequência de valores no seu construtor (o valor base e as keys).

  • Ao passar um array ou ponteiro como argumento, não esqueça de passar o tamanho logo em seguida, como ... "alfafa", 6, .... Provavelmente se você esquecer ele vai te avisar de forma bem legal que você esqueceu disso.
  • SuperMap é simples também, você pode inicializar um diretamente por um std::initializer de SuperPair que por natureza cada um recebe argumentos variáveis, então fica extremamente mais fácil, ou pode definir conforme roda o programa.

As classes


class data_any{
  void* d = nullptr;
  size_t siz = 0;
public:
  void set(T*, size_t);
  void set(const T*, size_t);
  void*& get();
  void* get() const;
  void unset();
  size_t size() const;
  bool isSet() const;
  operator==(const data_any&) const;
  isEq(const void*, size_t) const;
};

data_any é a base de como é salvo qualquer coisa no programa. Com esse cara fica mais fácil controlar ponteiros, porque você sabe qual o tamanho do que criou (ao contrário de um std::shared_ptr ou ponteiro comum). Composto internamente de um void* e um size_t, você pode alocar qualquer coisa por ele e permanecer com o tamanho (com base no tipo, então não há "tamanho * sizeof() do que você mandou", só "tamanho") passado ao gerar os dados.

  • set: cria um objeto ou array do tipo T com tamanho a ser definido (1 ou mais);
  • get: retorna o endereço de onde alocou;
  • unset: apaga a memória alocada;
  • size: retorna quanto de memória foi alocada (na chamada do set, dependente do tipo, por exemplo pode ser 4 int (4 bytes) ou 4 char (1 byte). Lembre-se do tipo que você gerou em primeiro lugar!);
  • isSet: retorna verdadeiro se há alguma memória alocada;
  • operator==: compara se o outro data_any é exatamente igual a ele em tamanho e conteúdo;
  • isEq: mesma coisa que o operator==, mas com void* e você passando manualmente o tamanho;

class SuperPair{
  std::vector<std::pair<std::type_index, data_any>> pairs;
  K value = K();
public:
  SuperPair(); // default
  SuperPair(const K&, Args...);
  SuperPair(const K&);
  
  void clear();
  
  void setKey(T(&)[]);
  void setKey(T*, size_t);
  void setKey(T&);

  void delKey(T);
  
  void setValue(const K&);
  const K* getValue() const;
  K* getValue();
  
  const K* operator[](T&) const;
  const K* operator[](T(&)[]) const;
  K* operator()(T&);
  K* operator()(T(&)[]);
  K* operator()(T*, size_t);
  
  bool hasKeyVal(T(&)[]) const;
  bool hasKeyVal(T*, size_t) const;
  bool hasKeyVal(T&) const;
  
  T getKeyVal(bool&, size_t&) const;
  
  bool hasType(T(&)[]) const;
  bool hasType(T*, size_t) const;
  bool hasType(T&) const;
  bool hasType() const;

  amIThis(SuperPair*&) const;
};

SuperPair é, em geral, semelhante a um std::map. Em geral você pode acessar as coisas com operator[], mas aí que muda um pouco: o SuperPair tem tanto o operator[] quanto operator(), e eles têm de fato propósitos diferentes. Se você quer garantir que o valor não seja alterado, use operator[], mas se quiser, operator(). Assim fica um pouco mais fácil de controlar as coisas, mas, se quiser, use só operator(). Internamente um SuperPair contém um std::vector de pares de std::type_index e data_any. Dessa maneira ele pode gerar qualquer coisa e salvar o tipo num par indefinidas vezes.

  • SuperPair: O construtor dessa classe permite que você a inicialize diretamente com seu valor e várias keys, inicialize apenas com seu valor, ou apenas crie-o normalmente para depois definir tudo;
  • clear: Essa função limpa o std::vector interno, apagando todas as keys. Ele não apaga o valor salvo, só as keys;
  • setKey: Define ou redefine o valor de um tipo de key (por exemplo char*);
  • delKey: Apaga a key do tipo que mandar a ele ou que você definir dentro dos <>;
  • setValue: Define o valor o qual todas essas keys apontam;
  • getValue(): Pega o ponteiro para o valor desse SuperPair;
  • operator[]: Acessa (no modo const) o valor se a key passada bater com a key definida;
  • operator(): Acessa o valor se a key passada bater com a key definida (direto ponteiro);
  • getKeyVal: Retorna o valor de uma key do tipo (se definida) passando true para o bool& do argumento e o tamanho da key (se for array pode retornar maior que 1) no size_t&. Se não encontrar nenhuma key, retornará um valor indeterminado e dará false ao argumento bool&;
  • hasType: Retorna true se há uma key do tipo que deseja testar;
  • amIThis: Retorna true se o ponteiro que mandou corresponde ao ponteiro dele mesmo;

class SuperMap {
  std::vector<SuperPair<K>> keys;
public:
  SuperMap();
  SuperMap(std::initializer_list<SuperPair<K>>);
  SuperMap(const SuperMap&);
  SuperMap& operator=(const SuperMap&);

  void clear();

  auto begin() const;
  auto end() const;

  void add(SuperPair<K>);

  const K* operator[](T) const;
  const K* operator[](T(&)[]) const;
  K* operator()(T);
  K* operator()(T(&)[]);
  K* operator()(T*, size_t);

  SuperPair<K>* getPair(J) const;
  SuperPair<K>* getPair(J(&)[]) const;
  SuperPair<K>* getPair(T*, size_t) const;

  void delPair(SuperPair<K>*);

  bool isThere() const;
};

SuperMap é uma classe que basicamente contém diversos SuperPair do mesmo tipo, mas com quaisquer keys (podem ser definidos independentemente por causa da forma como o sistema funciona). Dessa maneira, você pode ter qualquer coisa apontando pra alguma coisa em algum lugar dentro dessa gigante classe.

  • SuperMap: O construtor dessa classe permite que você inicie loucamente com vários SuperPair, que cada um permite iniciar de forma totalmente customizável, ou então de forma normal sem definir nenhum valor;
  • clear: Limpa todos os SuperPair do SuperMap;
  • begin: begin() do std::vector de SuperPair (útil para um for (auto& i : supermap){}, se quiser);
  • end: end() do std::vector de SuperPair (útil para um for (auto& i : supermap){}, se quiser);
  • add: Recebe um SuperPair e salva-o internamente;
  • operator[]: Acessa (no modo const) e retorna o valor correspondente à key, se tiver algum SuperPair definido com ela;
  • operator(): Acessa e retorna o valor correspondente à key, se tiver algum SuperPair definido com ela;
  • getPair: Retorna um SuperPair que corresponda com a key;
  • delPair: Apaga do std::vector interno o ponteiro correspondente;
  • isThere: Retorna se há algum SuperPair com esse tipo de key;

Funções assistentes


  • CHAR_INIT(a): Um macro para facilitar a criação direta de char* para a definição de uma das keys do SuperPair (ele já transforma a string em string, tamanho). Limite: 512.
  • strlen_s(char(&)[]): Uma função semelhante aos strlen por aí, só que pronta para receber diretamente um array (automaticamente interpreta o tamanho máximo do array por ele mesmo).
  • assert_cast(const T*, const Abort::abort_level): Uma função simples que causa Abort caso o ponteiro passado pra ela não seja diferente de nullptr. O tipo de Abort pode ser definido, sendo o padrão Abort::abort_level::GIVEUP. Se o ponteiro não for nulo, retorna ele mesmo.

Informações adicionais


Em geral você só vai usar o SuperMap, com talvez alguns pontos lidando com uns SuperPair, mas provavelmente você não vai querer encostar no data_any.


Como usar?


int main()
{
  SuperMap<int> mapp = { {1, CHAR_INIT("alfafa")}, {2, CHAR_INIT("potato"), 'p'} }; // CHAR_INIT é a própria string e seu tamanho, em sequência, o MACRO em si

  // exemplo de acesso
  printf_s("Value contained on \"alfafa\"      : %d\n", *assert_cast(mapp["alfafa"]));  // mostra 1
  printf_s("Value contained on \"potato\"      : %d\n", *assert_cast(mapp["potato"]));  // mostra 2

  *mapp("alfafa") = 20; // define o valor 20 para onde "alfafa" aponta

  printf_s("Value contained on const \"alfafa\": %d\n", *assert_cast(mapp["alfafa"]));  // mostra 20

  mapp.getPair("potato")->delKey<char*>(); // apaga a key char* dele, logo "potato" deixa de existir
  mapp.delPair(mapp.getPair("alfafa")); // apaga completamente o cara que contém a key "alfafa". Não se preocupe, tem verificação de nullptr em delPair() caso ele não encontre por algum motivo

  auto* ruf = mapp["alfafa"]; // tenta achar algum SuperPair com key "alfafa"
  auto* rug = mapp["potato"]; // tenta achar algum SuperPair com key "potato"
  auto* ruh = mapp['p'];      // tenta achar algum SuperPair com key 'p'

  printf_s("Value contained on \"alfafa\"      : %s\n", ruf ? std::to_string(*ruf).c_str() : "not found"); // not found
  printf_s("Value contained on \"potato\"      : %s\n", rug ? std::to_string(*rug).c_str() : "not found"); // not found
  printf_s("Value contained on \'p\'           : %s\n", ruh ? std::to_string(*ruh).c_str() : "not found"); // mostra 2

  mapp.clear(); // se não for usar mais, é uma boa prática deixar explícito pra limpar
}

Conclusão


Essas classes são extremamente versáteis dentro do programa e em diversas outras aplicações. Basicamente preparei uma base sem limites (até onde é possível no momento) para poder usar em situações adversas durante o programa. Enfim, SuperMap é de fato uma das classes mais interessantes do programa, junto com as outras relacionadas a ela.

Clone this wiki locally