Container em C

Programação C em geral

Moderadores: 51, guest2003

Container em C

Mensagempor chrdcv » 03 Jul 2016 20:22

cpp code
// Cria tabela de dispersão:
hash_t *hash_create (
size_t, // tamanho (em bytes) do tipo do container
size_t); // tamanho da tabela de dispersão (baseada na "função" de dispersão)

// Insere na tabela de dispersão:
int hash_insert (
hash_t *, // tipo
void *, // objeto a ser inserido
unsigned, // chave
void *(*)(void *), // invoca a criação do container que resolve colisão
void (*)(void *, void *, int *, int (*)(const void *, const void *)), // insere no cont.
int (*)(const void *, const void *)); // predicado para comparação


A invocação seria algo do tipo:
cpp code
// Criação da tabela hash:
if(hash_coll_rtype == HASHING_BY_BTREE)
h = hash_create(sizeof(btree_t *), hash_nelements);
else if(hash_coll_rtype == HASHING_BY_SBBTREE)
h = hash_create(sizeof(sbbtree_t *), hash_nelements);
// Inserção na tabela hash:
if(hash_coll_rtype == HASHING_BY_BTREE)
hash_ins = hash_insert (
h,
black_list_arr[idx],
black_list_arr[idx]->key,
(void*(*)(void *))(*btree_create),
(void(*)(void *, void *, int *, int (*)(const void *, const void *)))(*btree_insert),
(int(*)(const void *, const void *))(cmp));
else if(hash_coll_rtype == HASHING_BY_SBBTREE)
hash_ins = hash_insert (
h,
black_list_arr[idx],
black_list_arr[idx]->key,
(void*(*)(void *))(*sbbtree_create),
(void(*)(void *, void *, int *, int (*)(const void *, const void *)))(*sbbtree_insert),
(int(*)(const void *, const void *))(cmp));
Seu Madruga: "O trabalho não é ruim, ruim é ter que trabalhar"
Avatar do usuário
chrdcv
Dword
 
Mensagens: 1580
Registrado em: 13 Out 2006 14:13

Re: Container em C

Mensagempor Rodrigo_P_A » 07 Jul 2016 23:02

Desculpe ????

Enviado de meu SM-A700FD usando Tapatalk
---
Avatar do usuário
Rodrigo_P_A
Dword
 
Mensagens: 2236
Registrado em: 12 Out 2006 18:27
Localização: Osasco - S.P - Brasil

Re: Container em C

Mensagempor msamsoniuk » 07 Jul 2016 23:31

entao, eh bem por aih... achei que soh eu tinha visto! :v

Imagem

Rodrigo_P_A escreveu:Desculpe ????

Enviado de meu SM-A700FD usando Tapatalk
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Re: Container em C

Mensagempor chrdcv » 08 Jul 2016 20:39

Estou de volta com dúvidas, muitas dúvidas...

Em C++, o Stepanov juntamente com o Lee e o Stroustrup tiveram a sacada genial da STL através do uso de gabaritos (templates). Pelo que andei lendo, o Stepanov juntamente com o Lee chegaram mesmo a implementar o que seria um "esboço" da STL em Ada, mas creio que não deu muito certo devido as restrições da linguagem (ainda terei que ler mair sobre isso para ter uma opinião mais precisa). A grande sacada da STL é a implementação algoritmos capazes de operar em tipos "genéricos". Assim, um "map" em C++ é capaz de manipular caracteres, inteiros, tipos definidos pelo usuário ou ainda outro container. De maneira análoga temos o unordered_map que é uma espécie de função de dispersão (hash), onde é possivel através de predicados, organizar todos os dados de forma lexicográfica por exemplo. Tudo muito bem pensado e implementado.

Em contrapartida, em C temos o tipo opaco void * e é com ele que preciso trabalhar para desenvolver uma espécie de container para pesquisa de dados na memória primária -- função de dispersão - hash. Em um primeiro momento poderia trabalhar com as colisões utilizando uma lista encadeada, uma árvore binária, uma árvore binária com inserção pela raiz, uma árvore SBB (parecida com árvore rubro-negra - "red black tree"), um hash duplo ou ainda hash com endereçamento livre - open addressing. Entretanto, não estou interessado em desenvolver "funções" para cada tipo de hash acoplado ao método de resolução de colisão. Ao invés disso, penso que seria mais oportuno o desenvolvimento dos containeres tais como: lista, árvore binária, árvore binária com inserção pela raiz, árvore SBB, etc.. e depois ter um outro container hash que conforme container passado como parâmetro, aplica o método que resolve a colisão. Inicialmente pensei em algo assim:

Código: Selecionar todos
-- Criação da tabela hash:
   if(hash_coll_rtype == HASHING_BY_BINTREE)
      h = hash_create(sizeof(bintree_t *), hash_nelements);
    else if(hash_coll_rtype == HASHING_BY_SBBTREE)
      h = hash_create(sizeof(sbbtree_t *), hash_nelements);
-- Inserção na tabela hash:
      if(hash_coll_rtype == HASHING_BY_BINTREE)
        hash_ins = hash_insert (
          h,
          black_list_arr[idx],
          black_list_arr[idx]->key,
          (void*(*)(void *))(*bintree_create),
          (void(*)(void *, void *, int *, int (*)(const void *, const void *)))(*bintree_insert),
          (int(*)(const void *, const void *))(cmp));
      else if(hash_coll_rtype == HASHING_BY_SBBTREE)
        hash_ins = hash_insert (
          h,
          black_list_arr[idx],
          black_list_arr[idx]->key,
          (void*(*)(void *))(*sbbtree_create),
          (void(*)(void *, void *, int *, int (*)(const void *, const void *)))(*sbbtree_insert),
          (int(*)(const void *, const void *))(cmp));


O que acham da implementação? O meu interesse é não mais ter nenhum acoplamento entre hash e as demais implementações, baseado no fato de que a verificação de tipagem é um pouco fraca em C.

Teriam uma outra possibilidade de forma a ter os princípios expostos acima? Tenham em mente que não posso ter interdependência de bibliotecas (acoplamento). Assim, na unidade de tradução hash.c só posso ter hash.h e as demais bibliotecas do sistema, semelhante aspecto é dado para o caso dos demais containers, assim, em bintree.c só posso ter btree.h e as demais bibliotecas do sistema. Somente no método que a função hash é invocada é que posso ter as demais bibliotecas das implementações inclusas (por exemplo, na unidade de tradução main.c posso incluir hash.h, bintree.h, etc). Desta maneira consigo o desacoplamento total, que é o objetivo inicial. Há uma outra forma de fazer isso de forma mais simple EM C?

Agradeço antecipadamente pelas sugestões/críticas (sempre BEM vindas)!
Seu Madruga: "O trabalho não é ruim, ruim é ter que trabalhar"
Avatar do usuário
chrdcv
Dword
 
Mensagens: 1580
Registrado em: 13 Out 2006 14:13

Re: Container em C

Mensagempor msamsoniuk » 09 Jul 2016 04:36

enquanto eu lia, imaginei o cara da foto falando comigo... no final apenas consegui concordar com vc plenamente: duvidas e mais duvidas! :v

Imagem

bom, pelo pouco que entendi, vc gostaria de ter um void *h e, dependendo do tipo escolhido, criar diferentes tipos de tabelas hash apontadas por h... bom, nao sei se estas funcoes fazem parte de alguma biblioteca, ao menos nao encontrei nada similar no meu sistema (mas eh um BSD, talvez esteja meio desatualizado)... enfim, supondo que nao eh algo padrao do sistema, eu particularmente usaria uma abordagem diferente... partindo do pressuposto que struct hash_table e hash_create() sao algo tipo:

Código: Selecionar todos
// hash.h
#define HASHING_BY_BINTREE 1
#define HASHING_BY_SBBTREE 2
...

struct hash_table {

  int type;
  int size;
  void *table;
  int(*insert)(blablabla.);
  ...
};

// hash.c
#include <hash.h>
#include <sbbtree.h>
#include <bintree.h>

struct hash_table *hash_create(int type,int size)
{
  struct hash_table *tmp = malloc(sizeof(...));
  tmp->type = type;
  tmp->size = size;
  tmp->table = type==HASHING_BY_BINTREE ? bintree_create(blablabla) :
                      type==HASHING_BY_SBBTREE ? sbbtree_create(blablabla) : ...

  tmp->insert = type==HASHING_BY_BINTREE ? bintree_insert :
                      type==HASHING_BY_SBBTREE ? sbbtree_insert : ...
  ...
  ret tmp;
}


basicamente uma estrutura de dados que contem algo e uma funcao que popula essa estrutura de acordo com o tipo. isso seria uma interface entre as funcoes de hash e o resto da aplicacao, na pratica, a aplicacao ve hash.h e linka com hash.o (que pode ser uma libhash.so e conter e/ou apontar para bintree.so, sbbtree.so, etc). ateh acho que os type==algo ? ble : bla poderiam ser substituidos por algo tipo insert_by_type[type]. mas eu temo estar comecando a confudir C com verilog hahaha bom, eh um exemplo bem tosco e estou com preguica de digitar codigo longo... a interface ficaria bem simples:

Código: Selecionar todos
#include <hash.h>
...
struct hash_table *h = hash_create(type, size);
h->insert(h,lots of things here);
...
h->delete(h);


em essencia: *h eh uma estrutura de dados que contem um determinado dado (a tabela hash, mas conforme o tipo) e contem os metodos que o manipulam... o tipo hash_type pode ser mudado arbitrariamente e isso tem seu lado bom e ruim... no caso, h->insert() eh relativamente rapido e eficiente: ele jah populou os metodos que manipulam essa estrutura quando foi criada, entao h->insert() eh realmente rapido, nao precisa ficar testando type==... e pode chamar as funcoes diretamente. divertido eh quando vc tem algo tipo h->event[event](h)... quer dizer, vc tem um array de ponteiros para funcao, que na pratica sao metodos diferentes para manipular diferentes situacoes geradas externamente... parece estranho, mas funciona feito um relogio!

claro, tem que ter toda uma verificacao e previsao de falhas: se vc chamar um tipo nao especificado, o que ocorre com h? provavelmente NULL... mas e se h for valido, porem aquele metodo nao existe? provavelmente h->insert = NULL... mas h->insert() falharia miseravelmente. entao talvez h->insert caia em uma funcao de tratamento de excessao para rodar sem crashar e produzir um diagnostico se h nao eh NULL. em essencia, se criar a estrutura sempre certa, nao deve falhar. oh claro, isso eh C: nao tem this, tem que referenciar h em h->delete(h), senao a funcao nao sabe exatamente o que fazer! bom, nao sei se era algo nesse sentido... independente disso, espero ter sido tao vago quanto gostaria e tao obscuro quanto o assunto merece! :v
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Re: Container em C

Mensagempor Rodrigo_P_A » 09 Jul 2016 11:45

Acho que num da certo ser os tamanhos das structs são diferentes. Em c++ é mais fácil por causa do poliformismo

Enviado de meu SM-A700FD usando Tapatalk
---
Avatar do usuário
Rodrigo_P_A
Dword
 
Mensagens: 2236
Registrado em: 12 Out 2006 18:27
Localização: Osasco - S.P - Brasil

Re: Container em C

Mensagempor andre_luis » 09 Jul 2016 11:49

Eu achava que sabia C, mas confesso que depois de ler esse tópico fiquei deprimido...
"Por maior que seja o buraco em que você se encontra, relaxe, porque ainda não há terra em cima."
Avatar do usuário
andre_luis
Dword
 
Mensagens: 5447
Registrado em: 11 Out 2006 18:27
Localização: Brasil - RJ

Re: Container em C

Mensagempor msamsoniuk » 09 Jul 2016 14:09

Rodrigo_P_A escreveu:Acho que num da certo ser os tamanhos das structs são diferentes. Em c++ é mais fácil por causa do poliformismo

Enviado de meu SM-A700FD usando Tapatalk


nao tem problema... a tipagem da linguagem C eh apenas superficial. de fato, chamar de fracamente tipada eh um elogio! a linguagem C eh realmente bastante flexivel e, efetivamente, consegue reproduzir qq especie de mecanismo de outras linguagens, variando claro, o trabalho que vc vai ter para tal. um exemplo talvez mais simples e facil de entender, onde eu quero ter estruturas de tamanhos diferentes (vetores x,y,z em float e strings):

Código: Selecionar todos
// no coisas.h
#define VECTOR 1
#define STRING 2
...

struct type_generic
{
  void (*init)(...);
}

struct type_string
{
  struct type_generic m;
  char s[1];
};

struct type_vector
{
  struct type_generic m;
  float x,y,z;
};

// no coisas.c
#include <coisas.h>
#include <myvector.h>
#include <mystring.h>

void *create_coisa(int type)
{
  switch(type)
  {
    case VECTOR:
      struct type_vector *tmp = (void *)malloc(sizeof(struct type_vector);
      tmp->m.init = init_vector;
      tmp->x = tmp->y = tmp.z = 0.0;
      return (void *)tmp;
    case STRING:
      struct type_string *tmp = (void *)malloc(sizeof(struct type_string);
      tmp->m.init = init_string;
      tmp->s[0] = 0;
      return (void *)tmp;
    ...
  }
}


daih na hora de usar:

Código: Selecionar todos
struct type_generic *a,*b;

a = create_coisa(VECTOR);
b = create_coisa(STRING);

a->init(a,x,y,z);
b->init(b,"string");


o create cria a e b de acordo com suas respectivas structs, que nem possuem o mesmo tamanho! independente, a funcao retorna ponteiros e eles apontam para areas na memoria. no caso, converte-se esses ponteiros na struct type_generic, que nesse caso eh comum e possui, portanto, o metodo init. na criacao atribuiu-se o init especifico para cada tipo, assim pode-se chamar sem erro. eventualmente, a checagem de parametros pode ser complexa, mas eh algo estilo printf(), onde os parametros serao puxados da stack pela funcao chamada. enfim, o init para o tipo vector vai pegar o ponteiro a e manipular segundo a struct type_vector, o init para o tipo string vai manipular b segundo a struct type_string. e elas definitivamente nao possuem o mesmo tamanho e/ou organizacao. funciona pq a->m.init() e b->m.init() foram corretamente inicializados com respectivas funcoes q sabem o que fazer, assim a chamada direta nao falha. claro, na falta de this, tem que tomar cuidado! seria catastrofico chamar o metodo para um tipo e passar outro:

a->m.init(b,x,y,z); // crash!

ah, antes que alguem pergunte... para o init de string, que possui s[1], teria que fazer um realloc() aumentando o tamanho de b de acordo com strlen. em ambos os casos, para destruir as structs, um delete() direto no ponteiro resolve. acho que isso ilustra como C pode ser bem agnostico sobre void *.
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Re: Container em C

Mensagempor Rodrigo_P_A » 09 Jul 2016 14:14

Sim Marcelo. Eu gosto da flexibilidade do c e sabendo usar ponteiros da pra fazer qualquer coisa.
Mas fazer isso em c++ por causa do polimorfismo fica mais fácil.
Na verdade eu só gosto do polimorfismo e dos constructs e destructs do c++. Num uso mais do que é estes recursos na maioria dos meus programas, desta forma fico bem mais próximo do c.
Qdo vejo templates malucos no c++ é no C não acho muito legal pois o código fica ilegível... mas aí é questão de gosto.

Enviado de meu SM-A700FD usando Tapatalk
---
Avatar do usuário
Rodrigo_P_A
Dword
 
Mensagens: 2236
Registrado em: 12 Out 2006 18:27
Localização: Osasco - S.P - Brasil

Re: Container em C

Mensagempor xultz » 09 Jul 2016 18:37

Eu achei que o código ficou perfeito, se a finalidade é criar programas que ninguém além de você vai entender. Vai cumprir 100% com esta finalidade.
98% das vezes estou certo, e não estou nem aí pros outros 3%.
Avatar do usuário
xultz
Dword
 
Mensagens: 3001
Registrado em: 13 Out 2006 18:41
Localização: Curitiba

Re: Container em C

Mensagempor KrafT » 09 Jul 2016 20:51

Isso daí tá parecendo o corpo de um maluco que foi explodir um caixa eletrônico aqui na região e não usou pavio de retardo...
"..."Come to the edge," he said. And so they came. And he pushed them. And they flew."― Guillaume Apollinaire
Avatar do usuário
KrafT
Dword
 
Mensagens: 2228
Registrado em: 11 Out 2006 14:15
Localização: Blumenau -SC

Re: Container em C

Mensagempor msamsoniuk » 09 Jul 2016 21:45

eu acho que voces estao ficando velhos e molengas hein... estao comendo muita tortinha de maca no mcdonalds! :O
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Re: Container em C

Mensagempor chrdcv » 11 Jul 2016 18:19

msamsoniuk escreveu:eu acho que voces estao ficando velhos e molengas hein... estao comendo muita tortinha de maca no mcdonalds! :O


https://www.youtube.com/watch?v=1S0_7AC89mw
Seu Madruga: "O trabalho não é ruim, ruim é ter que trabalhar"
Avatar do usuário
chrdcv
Dword
 
Mensagens: 1580
Registrado em: 13 Out 2006 14:13

Re: Container em C

Mensagempor chrdcv » 11 Jul 2016 18:20

andre_teprom escreveu:Eu achava que sabia C, mas confesso que depois de ler esse tópico fiquei deprimido...


Eu tenho certeza que não sei, mas tenho praticado bastante ultimamente!
Seu Madruga: "O trabalho não é ruim, ruim é ter que trabalhar"
Avatar do usuário
chrdcv
Dword
 
Mensagens: 1580
Registrado em: 13 Out 2006 14:13

Re: Container em C

Mensagempor chrdcv » 11 Jul 2016 19:02

Marcelo Sam* mais uma vez, obrigado pela ajuda. No resto das minhas férias escolares de julho, trabalharei mais no código e postarei os resultados para crítica (caso tenha tempo e disponibilidade para dar uma olhada seria muito bom alguém com a tua experiência ir passando algumas dicas interessantes a serem adotadas).

Uma coisa que venho pensando refere-se a multiprocessamento. Como a Glibc e a libc adaptaram-se aos "novos" tempos? Houve re-escrita?
Seu Madruga: "O trabalho não é ruim, ruim é ter que trabalhar"
Avatar do usuário
chrdcv
Dword
 
Mensagens: 1580
Registrado em: 13 Out 2006 14:13

Próximo

Voltar para Visual C++/C/C++/C#

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

x