Commit 0d231da9 authored by Enzo Bonggio's avatar Enzo Bonggio
Browse files

string_map + esqueleto

parent e6aec85b
...@@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD 11) ...@@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -ggdb3 -g") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -ggdb3 -g")
# Leemos todos los archivos fuentes en ./src # Leemos todos los archivos fuentes en ./src
file(GLOB SOURCE_FILES src/*.cpp src/*.h) file(GLOB SOURCE_FILES src/*.cpp src/*.h src/*.hpp)
# Leemos todos los archivos de test en ./tests # Leemos todos los archivos de test en ./tests
file(GLOB TEST_SOURCES tests/*.cpp) file(GLOB TEST_SOURCES tests/*.cpp)
......
...@@ -3,140 +3,175 @@ ...@@ -3,140 +3,175 @@
#include <tuple> #include <tuple>
#include <algorithm> #include <algorithm>
BaseDeDatos::BaseDeDatos(){}; BaseDeDatos::BaseDeDatos() {};
void BaseDeDatos::crearTabla(const string &nombre, void BaseDeDatos::crearTabla(const string &nombre,
const linear_set<string> &claves, const linear_set<string> &claves,
const vector<string> &campos, const vector<string> &campos,
const vector<Dato> &tipos) { const vector<Dato> &tipos) {
_nombres_tablas.fast_insert(nombre); _nombres_tablas.fast_insert(nombre);
_tablas.fast_insert(make_pair(nombre, Tabla(claves, campos, tipos))); _tablas.fast_insert(make_pair(nombre, Tabla(claves, campos, tipos)));
} }
void BaseDeDatos::agregarRegistro(const Registro &r, const string &nombre) { void BaseDeDatos::agregarRegistro(const Registro &r, const string &nombre) {
Tabla &t = _tablas.at(nombre); Tabla &t = _tablas.at(nombre);
t.agregarRegistro(r); t.agregarRegistro(r);
} }
const linear_set<string> &BaseDeDatos::tablas() const { return _nombres_tablas; } const linear_set<string> &BaseDeDatos::tablas() const { return _nombres_tablas; }
const Tabla &BaseDeDatos::dameTabla(const string &nombre) const { const Tabla &BaseDeDatos::dameTabla(const string &nombre) const {
return _tablas.at(nombre); return _tablas.at(nombre);
} }
int BaseDeDatos::uso_criterio(const BaseDeDatos::Criterio &criterio) const { int BaseDeDatos::uso_criterio(const BaseDeDatos::Criterio &criterio) const {
if (_uso_criterios.count(criterio)) { if (_uso_criterios.count(criterio)) {
return _uso_criterios.at(criterio); return _uso_criterios.at(criterio);
} else { } else {
return 0; return 0;
} }
} }
bool BaseDeDatos::registroValido(const Registro &r, bool BaseDeDatos::registroValido(const Registro &r,
const string &nombre) const { const string &nombre) const {
const Tabla &t = _tablas.at(nombre); const Tabla &t = _tablas.at(nombre);
return (t.campos() == r.campos() and _mismos_tipos(r, t) and return (t.campos() == r.campos() and _mismos_tipos(r, t) and
_no_repite(r, t)); _no_repite(r, t));
} }
bool BaseDeDatos::_mismos_tipos(const Registro &r, const Tabla &t) const { bool BaseDeDatos::_mismos_tipos(const Registro &r, const Tabla &t) const {
for (auto c : t.campos()) { for (auto c : t.campos()) {
if (r.dato(c).esNat() != t.tipoCampo(c).esNat()) { if (r.dato(c).esNat() != t.tipoCampo(c).esNat()) {
return false; return false;
}
} }
} return true;
return true;
} }
bool BaseDeDatos::_no_repite(const Registro &r, const Tabla &t) const { bool BaseDeDatos::_no_repite(const Registro &r, const Tabla &t) const {
list<Registro> filtrados(t.registros().begin(), t.registros().end()); list<Registro> filtrados(t.registros().begin(), t.registros().end());
for (auto clave : t.claves()) { for (auto clave : t.claves()) {
_filtrar_registros(clave, r.dato(clave), filtrados); _filtrar_registros(clave, r.dato(clave), filtrados);
} }
return filtrados.empty(); return filtrados.empty();
} }
list<Registro> & list<Registro> &
BaseDeDatos::_filtrar_registros(const string &campo, const Dato &valor, BaseDeDatos::_filtrar_registros(const string &campo, const Dato &valor,
list<Registro> &registros) const { list<Registro> &registros) const {
return _filtrar_registros(campo, valor, registros, true); return _filtrar_registros(campo, valor, registros, true);
} }
list<Registro> &BaseDeDatos::_filtrar_registros(const string &campo, list<Registro> &BaseDeDatos::_filtrar_registros(const string &campo,
const Dato &valor, const Dato &valor,
list<Registro> &registros, list<Registro> &registros,
bool igualdad) const { bool igualdad) const {
auto iter = registros.begin(); auto iter = registros.begin();
while ( iter != registros.end()) { while (iter != registros.end()) {
auto now = iter; auto now = iter;
iter++; iter++;
if ((not igualdad) xor now->dato(campo) != valor) { if ((not igualdad) xor now->dato(campo) != valor) {
registros.erase(now); registros.erase(now);
}
} }
}
return registros; return registros;
} }
pair<vector<string>, vector<Dato> > BaseDeDatos::_tipos_tabla(const Tabla &t) { pair<vector<string>, vector<Dato> > BaseDeDatos::_tipos_tabla(const Tabla &t) {
vector<string> res_campos; vector<string> res_campos;
vector<Dato> res_tipos; vector<Dato> res_tipos;
for (auto c : t.campos()) { for (auto c : t.campos()) {
res_campos.push_back(c); res_campos.push_back(c);
res_tipos.push_back(t.tipoCampo(c)); res_tipos.push_back(t.tipoCampo(c));
} }
return make_pair(res_campos, res_tipos); return make_pair(res_campos, res_tipos);
} }
bool BaseDeDatos::criterioValido(const Criterio &c, bool BaseDeDatos::criterioValido(const Criterio &c,
const string &nombre) const { const string &nombre) const {
const Tabla &t = _tablas.at(nombre); const Tabla &t = _tablas.at(nombre);
for (auto restriccion : c) { for (auto restriccion : c) {
if (not t.campos().count(restriccion.campo())) { if (not t.campos().count(restriccion.campo())) {
return false; return false;
} }
if (t.tipoCampo(restriccion.campo()).esNat() != if (t.tipoCampo(restriccion.campo()).esNat() !=
restriccion.dato().esNat()) { restriccion.dato().esNat()) {
return false; return false;
}
} }
} return true;
return true;
} }
Tabla BaseDeDatos::busqueda(const BaseDeDatos::Criterio &c, Tabla BaseDeDatos::busqueda(const BaseDeDatos::Criterio &c,
const string &nombre) { const string &nombre) {
if (_uso_criterios.count(c)) { if (_uso_criterios.count(c)) {
_uso_criterios.at(c)++; _uso_criterios.at(c)++;
} else { } else {
_uso_criterios.fast_insert(make_pair(c, 1)); _uso_criterios.fast_insert(make_pair(c, 1));
} }
const Tabla &ref = dameTabla(nombre); const Tabla &ref = dameTabla(nombre);
auto campos_datos = _tipos_tabla(ref); auto campos_datos = _tipos_tabla(ref);
Tabla res(ref.claves(), campos_datos.first, campos_datos.second); Tabla res(ref.claves(), campos_datos.first, campos_datos.second);
list<Registro> regs(ref.registros().begin(), ref.registros().end()); list<Registro> regs(ref.registros().begin(), ref.registros().end());
for (auto restriccion : c) { for (auto restriccion : c) {
_filtrar_registros(restriccion.campo(), restriccion.dato(), _filtrar_registros(restriccion.campo(), restriccion.dato(),
regs, restriccion.igual()); regs, restriccion.igual());
} }
for (auto r : regs) { for (auto r : regs) {
res.agregarRegistro(r); res.agregarRegistro(r);
} }
return res; return res;
} }
linear_set<BaseDeDatos::Criterio> BaseDeDatos::top_criterios() const { linear_set<BaseDeDatos::Criterio> BaseDeDatos::top_criterios() const {
linear_set<Criterio> ret; linear_set<Criterio> ret;
int max = 0; int max = 0;
for (auto crit_count : _uso_criterios) { for (auto crit_count : _uso_criterios) {
if (crit_count.second >= max) { if (crit_count.second >= max) {
if (crit_count.second > max) { if (crit_count.second > max) {
ret = linear_set<Criterio>(); ret = linear_set<Criterio>();
max = crit_count.second; max = crit_count.second;
} }
ret.fast_insert(crit_count.first); ret.fast_insert(crit_count.first);
}
} }
} return ret;
return ret; }
void BaseDeDatos::crearIndice(const string tabla, const string columna) {
}
BaseDeDatos::joinIterator BaseDeDatos::join(string tabla1, string tabla2, string campo) {
// Tabla t1 = _tablas.at(tabla1);
// Tabla t2 = _tablas.at(tabla2);
//
// linear_set<string> resultClaves;
// vector<string> campos;
// vector<Dato> tipos;
//
// for(auto &c:t1.campos()) {
// campos.push_back(c);
// tipos.push_back(t1.tipoCampo(c));
// }
// for(auto &c:t2.campos()) {
// campos.push_back(c);
// tipos.push_back(t2.tipoCampo(c));
// }
//
// Tabla *joinTabla = new Tabla(resultClaves, campos, tipos);
//
// for (auto it = t1.registros_begin(); it != it.; ++it) {
//
// }
return *(new BaseDeDatos::joinIterator());
}
BaseDeDatos::joinIterator BaseDeDatos::join_end() {
return *(new BaseDeDatos::joinIterator());
} }
...@@ -27,143 +27,151 @@ using namespace std; ...@@ -27,143 +27,151 @@ using namespace std;
class BaseDeDatos { class BaseDeDatos {
public: public:
/** @brief Criterio de búsqueda para una base de datos */ /** @brief Criterio de búsqueda para una base de datos */
typedef linear_set<Restriccion> Criterio; typedef linear_set<Restriccion> Criterio;
/** class joinIterator;
* @brief Inicializa una base de datos sin tablas.
* /**
* \pre true * @brief Inicializa una base de datos sin tablas.
* \post \P{this} = nuevaDB *
* * \pre true
* \complexity{\O(1)} * \post \P{this} = nuevaDB
*/ *
BaseDeDatos(); * \complexity{\O(1)}
*/
/** BaseDeDatos();
* @brief Crea una nueva tabla en la base de datos.
* /**
* @param nombre Nombre identificador de la tabla * @brief Crea una nueva tabla en la base de datos.
* @param claves Claves de la tabla a crear *
* @param campos Campos de la tabla a crear * @param nombre Nombre identificador de la tabla
* @param tipos Tipos para los campos de la tabla a crear * @param claves Claves de la tabla a crear
* * @param campos Campos de la tabla a crear
* \pre db = \P{this} \LAND * @param tipos Tipos para los campos de la tabla a crear
* \LNOT (nombre \IN tablas(\P{this})) \LAND *
* \LAND \LNOT \EMPTYSET?(claves) \LAND * \pre db = \P{this} \LAND
* \FORALL (c: campo) c \IN claves \IMPLICA c \IN campos \LAND * \LNOT (nombre \IN tablas(\P{this})) \LAND
* long(campos) = long(tipos) \LAND sinRepetidos(campos) * \LAND \LNOT \EMPTYSET?(claves) \LAND
* \post \P{this} = agregarTabla(nuevaTabla(claves, nuevoRegistro(campos, tipos)), db) * \FORALL (c: campo) c \IN claves \IMPLICA c \IN campos \LAND
* * long(campos) = long(tipos) \LAND sinRepetidos(campos)
* \complexity{\O(C)} * \post \P{this} = agregarTabla(nuevaTabla(claves, nuevoRegistro(campos, tipos)), db)
*/ *
void crearTabla(const string &nombre, const linear_set<string> &claves, * \complexity{\O(C)}
const vector<string> &campos, const vector<Dato> &tipos); */
void crearTabla(const string &nombre, const linear_set<string> &claves,
/** const vector<string> &campos, const vector<Dato> &tipos);
* @brief Agrega un registro a la tabla parámetro
* /**
* @param r Registro a agregar * @brief Agrega un registro a la tabla parámetro
* @param nombre Nombre de la tabla donde se agrega el registro *
* * @param r Registro a agregar
* \pre db = \P{this} \LAND nombre \IN tablas(\P{this}) \LAND * @param nombre Nombre de la tabla donde se agrega el registro
* puedoInsertar?(r, dameTabla(\P{this})) *
* \post \P{this} = insertarEntrada(r, nombre, db) * \pre db = \P{this} \LAND nombre \IN tablas(\P{this}) \LAND
* * puedoInsertar?(r, dameTabla(\P{this}))
* \complexity{\O(T + copy(reg))} * \post \P{this} = insertarEntrada(r, nombre, db)
*/ *
void agregarRegistro(const Registro &r, const string &nombre); * \complexity{\O(T + copy(reg))}
*/
/** void agregarRegistro(const Registro &r, const string &nombre);
* @brief Devuelve el conjunto de tablas existentes en la base.
* /**
* El conjunto de nombres se devuelve por referencia no-modificable. * @brief Devuelve el conjunto de tablas existentes en la base.
* *
* \pre true * El conjunto de nombres se devuelve por referencia no-modificable.
* \post \P{res} = tablas(\P{this}) *
* * \pre true
* \complexity{\O(1)} * \post \P{res} = tablas(\P{this})
*/ *
const linear_set<string> &tablas() const; * \complexity{\O(1)}
*/
/** const linear_set<string> &tablas() const;
* @brief Devuelve la tabla asociada al nombre.
* /**
* La tabla se devuelve por referencia no modificable. * @brief Devuelve la tabla asociada al nombre.
* *
* @param nombre Nombre de la tabla buscada. * La tabla se devuelve por referencia no modificable.
* *
* \pre nombre \IN tablas(\P{this}) * @param nombre Nombre de la tabla buscada.
* \post \P{res} = dameTabla(nombre, \P{this}) *
* * \pre nombre \IN tablas(\P{this})
* \complexity{O(T)} * \post \P{res} = dameTabla(nombre, \P{this})
*/ *
const Tabla &dameTabla(const string &nombre) const; * \complexity{O(T)}
*/
/** const Tabla &dameTabla(const string &nombre) const;
* @brief Devuelve la cantidad de usos que tiene un criterio
* /**
* @param criterio Criterio por el cual se consulta. * @brief Devuelve la cantidad de usos que tiene un criterio
* *
* \pre nombre \IN tablas(\P{this}) * @param criterio Criterio por el cual se consulta.
* \post \P{res} = usoCriterio(criterio, \P{this}) *
* * \pre nombre \IN tablas(\P{this})
* \complexity{\O(#cs * cmp(Criterio))} * \post \P{res} = usoCriterio(criterio, \P{this})
*/ *
int uso_criterio(const Criterio &criterio) const; * \complexity{\O(#cs * cmp(Criterio))}
*/
/** int uso_criterio(const Criterio &criterio) const;
* @brief Evalúa si un registro puede ingresarse en la tabla parámetro.
* /**
* @param r Registro a ingresar en la tabla. * @brief Evalúa si un registro puede ingresarse en la tabla parámetro.
* @param nombre Nombre de la tabla. *
* * @param r Registro a ingresar en la tabla.
* \pre nombre \IN tablas(\P{this}) * @param nombre Nombre de la tabla.
* \post \P{res} = puedoInsertar?(r, dameTabla(nombre, \P{this})) *
* * \pre nombre \IN tablas(\P{this})
* \complexity{\O(T + C^2 + (c * C + c * n * (C + L)))} * \post \P{res} = puedoInsertar?(r, dameTabla(nombre, \P{this}))
*/ *
bool registroValido(const Registro &r, const string &nombre) const; * \complexity{\O(T + C^2 + (c * C + c * n * (C + L)))}
*/
/** bool registroValido(const Registro &r, const string &nombre) const;
* @brief Evalúa si un criterio puede aplicarse en la tabla parámetro.
* /**
* @param c Criterio a utilizar. * @brief Evalúa si un criterio puede aplicarse en la tabla parámetro.
* @param nombre Nombre de la tabla. *
* * @param c Criterio a utilizar.
* \pre tabla \IN tablas(\P{this}) * @param nombre Nombre de la tabla.
* \post \P{res} = criterioValido(c, nombre, \P{this}) *
* * \pre tabla \IN tablas(\P{this})
* \complexity{\O(T + cr * C)} * \post \P{res} = criterioValido(c, nombre, \P{this})
*/ *
bool criterioValido(const Criterio &c, const string &nombre) const; * \complexity{\O(T + cr * C)}
*/
/** bool criterioValido(const Criterio &c, const string &nombre) const;
* @brief Devuelve el resultado de buscar en una tabla con un criterio.
* /**
* @param c Criterio de búsqueda utilizado. * @brief Devuelve el resultado de buscar en una tabla con un criterio.
* @param nombre Nombre de la tabla. *
* * @param c Criterio de búsqueda utilizado.
* \pre nombre \IN tablas(\P{this}) \LAND criterioValido(c, nombre, \P{this}) * @param nombre Nombre de la tabla.
* \post \P{res} = buscar(c, nombre, \P{this}) *
* * \pre nombre \IN tablas(\P{this}) \LAND criterioValido(c, nombre, \P{this})
* \complexity{\O(T + cs * cmp(Criterio) + cr * n * (C + L + copy(reg)))} * \post \P{res} = buscar(c, nombre, \P{this})
*/ *
Tabla busqueda(const Criterio &c, const string &nombre); * \complexity{\O(T + cs * cmp(Criterio) + cr * n * (C + L + copy(reg)))}
*/
/** Tabla busqueda(const Criterio &c, const string &nombre);
* @brief Devuelve los criterios de máximo uso.
* /**
* \pre true * @brief Devuelve los criterios de máximo uso.
* \post \FORALL (c : Criterio) [c \IN \P{res} \IFF *
* \FORALL (c' : Criterio) usoCriterio(c, db) >= usoCriterio(c', db)] * \pre true
* * \post \FORALL (c : Criterio) [c \IN \P{res} \IFF
* \complexity{\O(cs * copy(Criterio))} * \FORALL (c' : Criterio) usoCriterio(c, db) >= usoCriterio(c', db)]
*/ *
linear_set<Criterio> top_criterios() const; * \complexity{\O(cs * copy(Criterio))}
*/
linear_set<Criterio> top_criterios() const;
void crearIndice(string tabla, string columna);
joinIterator join(string tabla1, string tabla2, string columna);
joinIterator join_end();
private: private:
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
/** \name Representación /** \name Representación
* rep: basededatos \TO bool\n * rep: basededatos \TO bool\n
* rep(bd) \EQUIV * rep(bd) \EQUIV
...@@ -226,8 +234,8 @@ private: ...@@ -226,8 +234,8 @@ private:
* nueva(campo, valor, igualdad), registros) * nueva(campo, valor, igualdad), registros)
*/ */
list<Registro> &_filtrar_registros(const string &campo, const Dato &valor, list<Registro> &_filtrar_registros(const string &campo, const Dato &valor,
list<Registro> &registros, list<Registro> &registros,
bool igualdad) const; bool igualdad) const;
/** /**
* @brief Filtra la lista de registros parametro según el criterio. * @brief Filtra la lista de registros parametro según el criterio.
...@@ -253,6 +261,48 @@ private: ...@@ -253,6 +261,48 @@ private:
*/ */
pair<vector<string>, vector<Dato> > _tipos_tabla(const Tabla &t); pair<vector<string>, vector<Dato> > _tipos_tabla(const Tabla &t);
/** @} */ /** @} */
public:
class joinIterator {
public:
joinIterator() {
}
joinIterator operator++(int n) {
return (*this);
}
joinIterator &operator++() {
return (*this);
}
Registro &operator*() const {
return *(new Registro({"NONE"}, {datoStr("NOT IMPLEMENTED")}));
}
Registro *operator->() const {
return (new Registro({"NONE"}, {datoStr("NOT IMPLEMENTED")}));
}
friend std::ostream &operator<<(std::ostream &stream, const joinIterator &it) {
stream << "NOT IMPLEMENTED YET";
}
bool operator==(const joinIterator &other) const {
return true;
}
bool operator!=(const joinIterator &otro) const {
return !(*this == otro);
}
friend class string_map;
private:
};
}; };
#endif #endif
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <cassert> #include <cassert>
#include <string> #include <string>
#include <vector> #include <vector>
#include <ostream>
using std::string; using std::string;
using std::vector; using std::vector;
...@@ -16,7 +17,7 @@ using std::pair; ...@@ -16,7 +17,7 @@ using std::pair;
* - tiene operador == (con complejidad cmp(T)) * - tiene operador == (con complejidad cmp(T))
* - solo permite utilizar el operator[] si T tiene constructor por defecto * - solo permite utilizar el operator[] si T tiene constructor por defecto
*/ */
template < typename T > template<typename T>
class string_map { class string_map {
public: public:
typedef string key_type; typedef string key_type;
...@@ -26,52 +27,118 @@ public: ...@@ -26,52 +27,118 @@ public:
class iterator; class iterator;
class const_iterator; class const_iterator;
/** @brief Construye mapa vacio /** @brief Construye mapa vacio
* *
* \complexity{\O(1)} * \complexity{\O(1)}
*/ */
string_map(); string_map() {
root = new Nodo();
cantKeys = 0;
}
/** @brief Destruye mapa /** @brief Destruye mapa
* *
* \complexity{\O(sn * S)} * \complexity{\O(sn * S)}
*/ */
~string_map(); ~string_map() {
clear();
delete (root);
}
/** @brief Constructor por copia /** @brief Constructor por copia
* *
* \complexity{\O(sn * S * copy(T))} * \complexity{\O(sn * S * copy(T))}
*/ */
string_map(const string_map &); string_map(const string_map &toCopy) {
root = new Nodo;
cantKeys = 0;
for (const_iterator it = toCopy.begin();it != toCopy.end(); ++it) {
insert((*it));
}
}
void printAll() {
for (auto it = begin(); it != end(); ++it) {
auto element = (*it);
std::cout << element.first << std::endl;
}
}
/** @brief Operador de asignacion /** @brief Operador de asignacion
* *
* \complexity{\O(sn * S * copy(T))} * \complexity{\O(sn * S * copy(T))}
*/ */
string_map& operator=(const string_map &); string_map &operator=(const string_map &toCopy) {
root = new Nodo;
cantKeys = 0;
for (const_iterator it = toCopy.begin();it != toCopy.end(); ++it) {
insert((*it));
}
return (*this);
}
/** @brief Operadores de comparacion /** @brief Operadores de comparacion
* *
* \complexity{\O(sn * S * cmp(T))} * \complexity{\O(sn * S * cmp(T))}
*/ */
bool operator==(const string_map& otro) const; bool operator==(const string_map &other) const {
bool operator!=(const string_map& otro) const {return !(*this == otro);} if (cantKeys == other.cantKeys) {
const_iterator it = begin();
const_iterator itOther = other.begin();
key_type first, firstOther;
mapped_type second, secondOther;
while(it != end()) {
first = it->first;
firstOther = itOther->first;
second = it->second;
secondOther = itOther->second;
if (first.compare(firstOther) != 0 || second != secondOther) return false;
++it;
++itOther;
}
return true;
}
return false;
}
bool operator!=(const string_map &otro) const { return !(*this == otro); }
/** @brief Cantidad de apariciones de la clave (0 o 1) /** @brief Cantidad de apariciones de la clave (0 o 1)
* @param key clave a buscar * @param key clave a buscar
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
size_type count(const key_type &key) const; size_type count(const key_type &key) const {
auto tmp = root;
for (auto it:key) {
if (tmp->children[it - FIRST_CHAR] == NULL) {
return 0;
}
tmp = tmp->children[it - FIRST_CHAR];
}
return static_cast<size_type>(tmp->isEndOfWord);
}
/** @brief Devuelve cantidad de claves definidas */ /** @brief Devuelve cantidad de claves definidas */
size_t size() const; size_t size() const {
return cantKeys;
}
/** @brief devuelve true si size() == 0 */ /** @brief devuelve true si size() == 0 */
bool empty() const; bool empty() const {
return size() == 0;
}
/** @brief Acceso / definición de pares clave/valor /** @brief Acceso / definición de pares clave/valor
...@@ -79,11 +146,28 @@ public: ...@@ -79,11 +146,28 @@ public:
* @returns una referencia a la definicion. * @returns una referencia a la definicion.
* *
* \complexity{ * \complexity{
* * \O(S) si la clave esta definida * * \O(S) si la clave esta definida
* * \O(S) + copy(T) sino * * \O(S) + copy(T) sino
* } * }
*/ */
mapped_type &operator[](const key_type &key); mapped_type &operator[](const key_type &key) {
auto tmp = root;
for (auto it:key) {
auto letterPosition = static_cast<size_type>(it - FIRST_CHAR);
if (tmp->children[letterPosition] == NULL) {
tmp->children[letterPosition] = new Nodo();
tmp->children[letterPosition]->parent = tmp;
}
tmp = tmp->children[letterPosition];
}
if (!(tmp->isEndOfWord)) {
tmp->isEndOfWord = true;
tmp->value = new mapped_type();
++cantKeys;
}
return *(tmp->value);
}
/** @brief Acceso a una clave sin modificar mapa /** @brief Acceso a una clave sin modificar mapa
* @param key clave a acceder que debe existir previamente * @param key clave a acceder que debe existir previamente
...@@ -91,18 +175,42 @@ public: ...@@ -91,18 +175,42 @@ public:
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
mapped_type& at(const key_type& key); mapped_type &at(const key_type &key) {
auto tmp = root;
for (auto it:key) {
tmp = tmp->children[it - FIRST_CHAR];
}
return *(tmp->value);
}
/** @brief Acceso a una clave sin modificar mapa /** @brief Acceso a una clave sin modificar mapa
* @param key clave a acceder que debe existir previamente * @param key clave a acceder que debe existir previamente
* @returns una referencia const a la definicion. * @returns una referencia const a la definicion.
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
const mapped_type& at(const key_type& key) const; const mapped_type &at(const key_type &key) const {
auto tmp = root;
for (auto it:key) {
tmp = tmp->children[it - FIRST_CHAR];
}
return *(tmp->value);
}
/** @brief Vacia el mapa */ /** @brief Vacia el mapa */
void clear(); void clear() {
auto tmp = begin();
for (; tmp != end();) {
std::cout << "VOY A BORRAR " << tmp << std::endl;
tmp = erase(tmp);
}
if (root->isEndOfWord) {
root->isEndOfWord = false;
--cantKeys;
}
}
// Accesos con iteradores // Accesos con iteradores
...@@ -111,19 +219,34 @@ public: ...@@ -111,19 +219,34 @@ public:
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
iterator begin(); iterator begin() {
return iterator(this->root);
}
/* @brief iterador al fin de la coleccion /* @brief iterador al fin de la coleccion
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
iterator end(); iterator end() {
return iterator(this->root, "");
}
/// Versiones const de begin/end /// Versiones const de begin/end
const_iterator begin() const; const_iterator begin() const {
const_iterator end() const; return const_iterator(this->root);
const_iterator cbegin() const; }
const_iterator cend() const;
const_iterator end() const {
return const_iterator(this->root, "");
}
const_iterator cbegin() const {
return const_iterator(this->root);
}
const_iterator cend() const {
return const_iterator(NULL);
}
/** @brief busca una clave /** @brief busca una clave
* @param key clave a buscar * @param key clave a buscar
...@@ -131,7 +254,14 @@ public: ...@@ -131,7 +254,14 @@ public:
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
iterator find(const key_type &key); iterator find(const key_type &key) {
auto tmp = root;
for (auto it:key) {
tmp = tmp->children[it - FIRST_CHAR];
}
return iterator(tmp, key);
}
/** @brief busca una clave /** @brief busca una clave
* @param key clave a buscar * @param key clave a buscar
...@@ -139,7 +269,14 @@ public: ...@@ -139,7 +269,14 @@ public:
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
const_iterator find(const key_type &key) const; const_iterator find(const key_type &key) const {
auto tmp = root;
for (auto it:key) {
tmp = tmp->children[it - FIRST_CHAR];
}
return const_iterator(tmp, key);
}
/** @brief insercion /** @brief insercion
* *
...@@ -150,7 +287,28 @@ public: ...@@ -150,7 +287,28 @@ public:
* *
* \complexity{\O(S + copy(T))} * \complexity{\O(S + copy(T))}
*/ */
pair<iterator, bool> insert(const value_type &value); pair<iterator, bool> insert(const value_type &value) {
auto tmp = root;
bool isInserted = false;
for (auto it:value.first) {
if (tmp->children[it - FIRST_CHAR] == NULL) {
tmp->children[it - FIRST_CHAR] = new Nodo();
tmp->children[it - FIRST_CHAR]->parent = tmp;
}
tmp = tmp->children[it - FIRST_CHAR];
}
if (!(tmp->isEndOfWord)) {
tmp->isEndOfWord = true;
++cantKeys;
isInserted = true;
}
tmp->value = new mapped_type(value.second);
iterator it = iterator(tmp, value.first);
return pair<iterator, bool>(it, isInserted);
};
/** @brief eliminar una clave /** @brief eliminar una clave
* @param key clave a eliminar * @param key clave a eliminar
...@@ -158,7 +316,14 @@ public: ...@@ -158,7 +316,14 @@ public:
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
size_type erase(const key_type& key); size_type erase(const key_type &key) {
if (count(key)) {
find(key).erase();
--cantKeys;
return 1;
}
return 0;
}
/** @brief eliminar una clave mediante irerador /** @brief eliminar una clave mediante irerador
* @param pos iterador apuntando a clave a eliminar * @param pos iterador apuntando a clave a eliminar
...@@ -166,9 +331,340 @@ public: ...@@ -166,9 +331,340 @@ public:
* *
* \complexity{\O(S)} * \complexity{\O(S)}
*/ */
iterator erase(iterator pos); iterator erase(iterator pos) {
--cantKeys;
return pos.erase();
}
private: private:
static const int ALPHABET_SIZE = 94;
static const char FIRST_CHAR = ' ';
unsigned int cantKeys;
struct Nodo {
Nodo *children[ALPHABET_SIZE];
Nodo *parent;
T *value;
bool isEndOfWord;
Nodo() {
isEndOfWord = false;
parent = NULL;
for (int i = 0; i < ALPHABET_SIZE; i++) {
children[i] = NULL;
}
value = NULL;
}
};
Nodo *root;
public:
class const_iterator {
public:
const_iterator(Nodo *root) {
auto tmp = root;
actual = findLeftestWord(tmp);
}
const_iterator(Nodo *root, key_type str) {
actual = root;
printUtilVector = std::vector<char>(str.begin(), str.end());
}
const_iterator &operator=(const const_iterator &other) {
this->printUtilVector = other.printUtilVector;
this->actual = other.actual;
return (*this);
}
bool operator==(const const_iterator &other) const {
bool isSameActual = this->actual == other.actual;
bool isSamePrintUtilVector = this->printUtilVector == other.printUtilVector;
return isSameActual && isSamePrintUtilVector;
}
bool operator!=(const const_iterator &otro) const {
return !(*this == otro);
}
const const_iterator &operator++() {
if (actual->parent == NULL) {
return (*this);
}
actual = actual->parent;
char last;
last = printUtilVector.back();
printUtilVector.pop_back();
int leftOne = leftestOne(actual, static_cast<char>(last + 1));
if (leftOne == -1) {
if (actual->isEndOfWord) {
return (*this);
}
// recursion
return ++(*this);
}
printUtilVector.push_back(FIRST_CHAR + leftOne);
actual = findLeftestWord(actual->children[leftOne]);
return (*this);
}
const const_iterator operator++(int n) {
const_iterator final = NULL;
for (int i = 0; i < n; i++) {
final = ++(*this);
}
return final;
}
const_iterator erase() {
if (leftestOne(actual, FIRST_CHAR) != -1) {
actual->isEndOfWord = false;
return ++(*this);
}
char last;
Nodo *tmp;
while (true) {
tmp = actual->parent;
// llegue al final
if (tmp == NULL) {
return (*this);
}
//borro y me quedo con el ultimo char y cambio actual y popeo
last = printUtilVector.back();
printUtilVector.pop_back();
delete (actual);
actual = tmp;
actual->children[last - FIRST_CHAR] = NULL;
if (actual->isEndOfWord) {
return (*this);
}
auto leftOne = leftestOne(actual, last);
if (leftOne != -1) {
actual = actual->children[leftOne];
printUtilVector.push_back(leftOne + FIRST_CHAR);
return findLeftestWord(actual);
}
}
}
value_type &operator*() const {
key_type key = key_type(printUtilVector.begin(), printUtilVector.end());
mapped_type value = *(actual->value);
auto *pair = new value_type(key, value);
return *pair;
}
value_type *operator->() const {
key_type key = key_type(printUtilVector.begin(), printUtilVector.end());
mapped_type value = *(actual->value);
auto *pair = new value_type(key, value);
return pair;
}
friend std::ostream &operator<<(std::ostream &stream, const const_iterator &it) {
if (it.actual->parent != NULL) {
stream << "primero: " << it->first;
} else stream << "es el fin";
return stream;
}
friend class string_map;
private:
Nodo *actual;
std::vector<char> printUtilVector;
Nodo *findLeftestWord(Nodo *tmp) {
int leftOne = 0;
while (tmp != NULL && leftOne != -1) {
leftOne = leftestOne(tmp, FIRST_CHAR);
if (leftOne != -1) {
printUtilVector.push_back(static_cast<char &&>(FIRST_CHAR + leftOne));
tmp = tmp->children[leftOne];
}
}
return tmp;
}
int leftestOne(Nodo *tmp, char last) {
for (int i = last - FIRST_CHAR; i < ALPHABET_SIZE; i++) {
if ((tmp->children[i]) != NULL) return i;
}
return -1;
}
};
class iterator {
public:
iterator(Nodo *root) {
auto tmp = root;
actual = findLeftestWord(tmp);
}
iterator(Nodo *root, key_type str) {
actual = root;
printUtilVector = std::vector<char>(str.begin(), str.end());
}
iterator &operator=(const iterator &other) {
this->printUtilVector = other.printUtilVector;
this->actual = other.actual;
return (*this);
}
bool operator==(const iterator &other) const {
bool isSameActual = this->actual == other.actual;
bool isSamePrintUtilVector = this->printUtilVector == other.printUtilVector;
return isSameActual && isSamePrintUtilVector;
}
bool operator!=(const iterator &otro) const {
return !(*this == otro);
}
iterator &operator++() {
if (actual->parent == NULL) {
return (*this);
}
actual = actual->parent;
char last;
last = printUtilVector.back();
printUtilVector.pop_back();
int leftOne = leftestOne(actual, static_cast<char>(last + 1));
if (leftOne == -1) {
if (actual->isEndOfWord) {
return (*this);
}
// recursion
return ++(*this);
}
printUtilVector.push_back(FIRST_CHAR + leftOne);
actual = findLeftestWord(actual->children[leftOne]);
return (*this);
}
iterator operator++(int n) {
iterator final = NULL;
for (int i = 0; i < n; i++) {
final = ++(*this);
}
return final;
}
iterator erase() {
if (leftestOne(actual, FIRST_CHAR) != -1) {
actual->isEndOfWord = false;
return ++(*this);
}
char last;
Nodo *tmp;
while (true) {
tmp = actual->parent;
// llegue al final
if (tmp == NULL) {
return (*this);
}
//borro y me quedo con el ultimo char y cambio actual y popeo
last = printUtilVector.back();
printUtilVector.pop_back();
delete(actual->value);
delete (actual);
actual = tmp;
actual->children[last - FIRST_CHAR] = NULL;
if (actual->isEndOfWord) {
return (*this);
}
auto leftOne = leftestOne(actual, last);
if (leftOne != -1) {
actual = actual->children[leftOne];
printUtilVector.push_back(leftOne + FIRST_CHAR);
actual = findLeftestWord(actual);
return (*this);
}
}
}
value_type &operator*() const {
key_type key = key_type(printUtilVector.begin(), printUtilVector.end());
mapped_type value = *(actual->value);
auto *pair = new value_type(key, value);
return *pair;
}
value_type *operator->() const {
key_type key = key_type(printUtilVector.begin(), printUtilVector.end());
mapped_type value = *(actual->value);
auto *pair = new value_type(key, value);
return pair;
}
friend std::ostream &operator<<(std::ostream &stream, const iterator &it) {
if (it.actual->parent != NULL) {
stream << "primero: " << it->first;
} else stream << "es el fin";
return stream;
}
friend class string_map;
private:
Nodo *actual;
std::vector<char> printUtilVector;
Nodo *findLeftestWord(Nodo *tmp) {
int leftOne = 0;
while (tmp != NULL && leftOne != -1) {
leftOne = leftestOne(tmp, FIRST_CHAR);
if (leftOne != -1) {
printUtilVector.push_back(static_cast<char &&>(FIRST_CHAR + leftOne));
tmp = tmp->children[leftOne];
}
}
return tmp;
}
int leftestOne(Nodo *tmp, char last) {
for (int i = last - FIRST_CHAR; i < ALPHABET_SIZE; i++) {
if ((tmp->children[i]) != NULL) return i;
}
return -1;
}
};
}; };
......
...@@ -693,7 +693,7 @@ TEST_F(DBAlumnos, crit_doble_otro_bool) { ...@@ -693,7 +693,7 @@ TEST_F(DBAlumnos, crit_doble_otro_bool) {
TEST_F(DBAlumnos, join_vacio) { TEST_F(DBAlumnos, join_vacio) {
db.crearIndice("alumnos", "LU"); db.crearIndice("alumnos", "LU");
auto begin = db.join("alumnos", "ex_alumnos", "LU"); auto begin = db.join("alumnos", "ex_alumnos", "LU");
auto end = db.join_end(); auto end = db.join_end();
EXPECT_EQ(begin, end); EXPECT_EQ(begin, end);
} }
...@@ -756,15 +756,15 @@ TEST_F(DBAlumnos, join_repetidos_ambos) { ...@@ -756,15 +756,15 @@ TEST_F(DBAlumnos, join_repetidos_ambos) {
db2.agregarRegistro(Registro({"Y", "Z"}, {Dato(1), Dato("B")}), "T2"); db2.agregarRegistro(Registro({"Y", "Z"}, {Dato(1), Dato("B")}), "T2");
db2.agregarRegistro(Registro({"Y", "Z"}, {Dato(2), Dato("C")}), "T2"); db2.agregarRegistro(Registro({"Y", "Z"}, {Dato(2), Dato("C")}), "T2");
Tabla t_join = Tabla({"X", "Y", "Z"}, {"X", "Y", "Z"}, Tabla t_join = Tabla({"X", "Y", "Z"}, {"X", "Y", "Z"},
{tipoNat, tipoNat, tipoStr}); {tipoNat, tipoNat, tipoStr});
t_join.agregarRegistro(Registro({"X", "Y", "Z"}, t_join.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(1), Dato(1), Dato("A")})); {Dato(1), Dato(1), Dato("A")}));
t_join.agregarRegistro(Registro({"X", "Y", "Z"}, t_join.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(1), Dato(1), Dato("B")})); {Dato(1), Dato(1), Dato("B")}));
t_join.agregarRegistro(Registro({"X", "Y", "Z"}, t_join.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(2), Dato(2), Dato("C")})); {Dato(2), Dato(2), Dato("C")}));
t_join.agregarRegistro(Registro({"X", "Y", "Z"}, t_join.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(3), Dato(2), Dato("C")})); {Dato(3), Dato(2), Dato("C")}));
db2.crearIndice("T1", "Y"); db2.crearIndice("T1", "Y");
...@@ -784,44 +784,44 @@ TEST_F(DBAlumnos, join_repetidos_ambos) { ...@@ -784,44 +784,44 @@ TEST_F(DBAlumnos, join_repetidos_ambos) {
TEST_F(DBAlumnos, join_campos_repetidos) { TEST_F(DBAlumnos, join_campos_repetidos) {
BaseDeDatos db2; BaseDeDatos db2;
db2.crearTabla("T1", {"X", "Y"}, {"X", "Y"}, {tipoNat, tipoNat}); db2.crearTabla("T1", {"X", "Y"}, {"X", "Y"}, {tipoNat, tipoNat});
db2.crearTabla("T2", {"X", "Y", "Z"}, {"X", "Y", "Z"}, db2.crearTabla("T2", {"X", "Y", "Z"}, {"X", "Y", "Z"},
{tipoNat, tipoNat, tipoStr}); {tipoNat, tipoNat, tipoStr});
/* /*
* T1 T2 * T1 T2
* | X | Y | | X | Y | Z | * | X | Y | | X | Y | Z |
* | 1 | 1 | | 1 | 1 | A | * | 1 | 1 | | 1 | 1 | A |
* | 2 | 2 | | 3 | 2 | C | * | 2 | 2 | | 3 | 2 | C |
* *
* T1 ~ T2 (Y) * T1 ~ T2 (Y)
* | X | Y | Z | * | X | Y | Z |
* | 1 | 1 | A | * | 1 | 1 | A |
* | 2 | 2 | C | * | 2 | 2 | C |
* *
* T2 ~ T1 (Y) * T2 ~ T1 (Y)
* | X | Y | Z | * | X | Y | Z |
* | 1 | 1 | A | * | 1 | 1 | A |
* | 3 | 2 | C | * | 3 | 2 | C |
* *
*/ */
db2.agregarRegistro(Registro({"X", "Y"}, {Dato(1), Dato(1)}), "T1"); db2.agregarRegistro(Registro({"X", "Y"}, {Dato(1), Dato(1)}), "T1");
db2.agregarRegistro(Registro({"X", "Y"}, {Dato(2), Dato(2)}), "T1"); db2.agregarRegistro(Registro({"X", "Y"}, {Dato(2), Dato(2)}), "T1");
db2.agregarRegistro(Registro({"X", "Y", "Z"}, db2.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(1), Dato(1), Dato("A")}), "T2"); {Dato(1), Dato(1), Dato("A")}), "T2");
db2.agregarRegistro(Registro({"X", "Y", "Z"}, db2.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(3), Dato(2), Dato("C")}), "T2"); {Dato(3), Dato(2), Dato("C")}), "T2");
Tabla t_join_a = Tabla({"X", "Y", "Z"}, {"X", "Y", "Z"}, Tabla t_join_a = Tabla({"X", "Y", "Z"}, {"X", "Y", "Z"},
{tipoNat, tipoNat, tipoStr}); {tipoNat, tipoNat, tipoStr});
t_join_a.agregarRegistro(Registro({"X", "Y", "Z"}, t_join_a.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(1), Dato(1), Dato("A")})); {Dato(1), Dato(1), Dato("A")}));
t_join_a.agregarRegistro(Registro({"X", "Y", "Z"}, t_join_a.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(2), Dato(2), Dato("C")})); {Dato(2), Dato(2), Dato("C")}));
Tabla t_join_b = Tabla({"X", "Y", "Z"}, {"X", "Y", "Z"}, Tabla t_join_b = Tabla({"X", "Y", "Z"}, {"X", "Y", "Z"},
{tipoNat, tipoNat, tipoStr}); {tipoNat, tipoNat, tipoStr});
t_join_b.agregarRegistro(Registro({"X", "Y", "Z"}, t_join_b.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(1), Dato(1), Dato("A")})); {Dato(1), Dato(1), Dato("A")}));
t_join_b.agregarRegistro(Registro({"X", "Y", "Z"}, t_join_b.agregarRegistro(Registro({"X", "Y", "Z"},
{Dato(3), Dato(2), Dato("C")})); {Dato(3), Dato(2), Dato("C")}));
db2.crearIndice("T1", "X"); db2.crearIndice("T1", "X");
...@@ -832,7 +832,7 @@ TEST_F(DBAlumnos, join_campos_repetidos) { ...@@ -832,7 +832,7 @@ TEST_F(DBAlumnos, join_campos_repetidos) {
linear_set<Registro> join(begin, end); linear_set<Registro> join(begin, end);
EXPECT_EQ(join, t_join_a.registros()); EXPECT_EQ(join, t_join_a.registros());
begin = db2.join("T2", "T1", "Y"); begin = db2.join("T2", "T1", "Y");
end = db2.join_end(); end = db2.join_end();
......
...@@ -69,6 +69,7 @@ TEST(string_map_test, test_comparar) { ...@@ -69,6 +69,7 @@ TEST(string_map_test, test_comparar) {
EXPECT_FALSE(m1==m2); EXPECT_FALSE(m1==m2);
} }
TEST(string_map_test, test_copiar) { TEST(string_map_test, test_copiar) {
string_map<int> m1; string_map<int> m1;
m1["hola"] = 123; m1["hola"] = 123;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment