pax_global_header 0000666 0000000 0000000 00000000064 14043255270 0014514 g ustar 00root root 0000000 0000000 52 comment=4e53476f5a5ea3615ba8b4c163312b69b2812503
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/ 0000775 0000000 0000000 00000000000 14043255270 0022360 5 ustar 00root root 0000000 0000000 ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/ClonableHetero.cbp 0000664 0000000 0000000 00000002730 14043255270 0025736 0 ustar 00root root 0000000 0000000
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/Makefile 0000664 0000000 0000000 00000002266 14043255270 0024026 0 ustar 00root root 0000000 0000000 #
# Makefile pelda a clonable hetero feladat megoldasanak forditasara
# gnumake valtozat
# Linuxokon es ural2-n is elerheto
#
PROG = clonable_hetero_test # a program neve (ezt allitjuk elo)
PROG_O = clonable_hetero_test.o # program object fajljai
PROG_H = clonable_hetero_store.hpp bacterium.h gtest_lite.h testclass.h clonable_bacterium.h clonable_testclass.h # program header fajljai
PROG_L = # program libjei
MTRACE_O = memtrace.o # memtrace object fajl
MTRACE_H = memtrace.h # memtrace es memcheck header fajlja
CXX = g++ # a C fordito neve
#CXX = clang++ # clang-ot (llvm) is erdemes kiprobalni
CXXFLAGS = -pedantic -Wall -Werror -std=gnu++98 # kapcsolok: legyen bobeszedu es pedans
CXXFLAGS += -ggdb -DMEMTRACE -DBACI_IS_VAN # es legyen debug info is
LDFLAGS = -ggdb # debug a linkelesnel
# osszes object, osszes header osszes lib
OBJS = $(PROG_O) $(MTRACE_O)
HEADS = $(PROG_H) $(MTRACE_H)
LIBS = $(PROG_L)
# alapertelmezett cel: program
.PHONY: all
all: $(PROG)
$(PROG): $(OBJS)
$(CXX) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
# feltetelezzuk, hogy az osszes obj fugg az osszes headertol
$(OBJS): $(HEADS)
# takaritas igeny szerint
.PHONY: clean
clean:
rm -f $(OBJS) $(PROG)
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/README.md 0000664 0000000 0000000 00000011353 14043255270 0023642 0 ustar 00root root 0000000 0000000 **Készítsen** heterogén kollekciók tárolásához sablon osztályt (**ClonableHeteroStore**),
ami egy belső *sorozattároló* segítségével tárolja a heterogén gyűjteményhez tartozó objektumok pointereit!
Sablonparaméterként vegye át a heterogén kollekció alaposztályát, a tároláshoz használt osztályt, valamint egy kivétel osztályt, amit hiba esetén eldob (ld. később)! Amennyiben ez nincs megadva, akkor az *std::out_of_range* kivételt dobja!
Amennyiben a tároló osztályt sem adják meg, akkor azt az *std::vector* sablonból hozza létre!
Az alábbi kódrészlet a sablon példányosítására mutat néhány példát:
ClonableHeteroStore t1;
ClonableHeteroStore, std::deque t2;
ClonableHeteroStore, MyClass> t3;
Ahol:
- t1 - *Ember\** típusú pointereket tárol *std::vector* sablon segítségével. Hiba esetén *std::out_of_range* kivételt dob.
- t2 - *Ember\** típusú pointereket tárol *std::deque* sablon segítségével. Hiba esetén *std::out_of_range* kivételt dob.
- t3 - *Valami\** típusú pointereket tárol *std::list* sablon segítségével. Hiba esetén *MyClass* kivételt dob.
Minimumkövetelmények a tárolásra használt osztályra vonatkozóan:
- A paraméterként átadott tárolótól elvárjuk, hogy legyen:
- létrehozható, megszüntethető, másolható, értékadható.
- A paraméterként átadott tárolótól elvárjuk, hogy valósítsa meg az alábbi metódusokat illetve típusokat:
- *value\_type* - a tárolt adat típusa.
- *iterator* - iterátor.
- *const\_iterator* - konstans iterátor.
- *begin()*, *end()* - visszaad egy iterátort, ami az első adatra, illetve az utolsó adat után mutat.
- *size()* - visszaadja a tárolt elemek számát.
- *push\_back()* - betesz egy új adatot a tárolóba - pontosabban az adat egy másolatát - a tárolt adatok után. Amennyiben helyhiány miatt ez nem sikerül, *std::bad_alloc* kivételt dob.
- *clear()* - törli a tárolót, azaz eldobja a tárolt adatokat, a tárolt darabszámot 0-ra állítja.
A fenti követelmények meglétét feltételezve **tervezze** meg a *ClonableHeteroStore* osztályt úgy, hogy az rendelkezzen az alábbi publikus metódusokkal, illetve illetve típusokkal:
- **const_iterator** - konstans iterátor.
- **begin()** - visszaad egy iterátort (*const\_iterator*) a belső tároló első elemére.
- **end()** - visszaad egy iterátort (*const\_iterator*), ami a belső tárolóban tárolt utolsó elem után mutat.
- **size_t size()** - megadja a tárolt pointerek számát
- **void add(p)** - beteszi a tárolóba a paraméterként kapott pointert.
Amennyiben a tárolóba már nem tudja betenni a pointert, dobjon kivételt!
- **void clear()** - törli (felszabadítja) a tárolóban tárolt objektumokat.
Legyenek a **ClonableHeteroStore** osztályból létrehozott objektumok másolhatók és szerepelhessenek értékadás bal oldalán is!
Támogassa a többszörös értékadást! **Tételezze fel**, hogy a tárolóban tárolt heterogén gyűjtemény osztályainak van **clone()** metódusa, ami egy teljes másolatot (deep copy) készít az adott objektumról.
**Feladatok:**
1. Töltse le az előkészített projektet a tárolóból!
[https://git.ik.bme.hu/Prog2/ell_feladat/ClonableHetero](https://git.ik.bme.hu/Prog2/ell_feladat/ClonableHetero.git)
2. Készítse el a **ClonableHeteroStore** osztályt a *clonable_hetero_store.hpp* állományban!
3. Tesztelje a megadott tesztprogrammal az új osztályt!
4. Elemezze a **ClonableTestClass**, a **ClonableTestClass1**, valamint a **ClonableTestClass2** osztályok megvalósítását a *clonable_testclass.h* állományban! A megvalósítás többszörös öröklést és virtuális alaposztályt használ. Értse meg, hogy miért van erre szükség!
5. A fentiek alapján hozzon létre klónozható baktériumokat, melyek kompatibilisek a **Bacterium**, valamint **Clonable** osztályokkal! Az osztályokat a *clonable_bacterium.h* fájlban implementálja!
6. Projekt szinten definiálja a **BACI\_IS\_VAN** makrót, fordítson és ismét teszteljen!
4. Amennyiben a tesztek jól futnak, töltse fel a *JPorta* feladatbeadó rendszerbe a **clonable\_bacterium.h** és **clonable\_hetero\_store.hpp** fájlokat!
**Megjegyzések:**
- Dinamikusan keletkező objektumok esetében fontos kérdés, hogy ki hozza létre és ki szünteti meg az objektumot, azaz mikor ki felel az objektumért. Ügyeljen arra, hogy a tárolónak átadott **"objektumért" a tároló felel**. Még akkor is, ha nem tudta elhelyezni azt a tárolóban.
- Azzal, hogy a tárolt elemek iterátorral is elérhetők, nincs szükség külön bejáró (traverse) tagfüggvényre. A tároló az iterátor segítségével egyszerűen bejárható.
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/bacterium.h 0000664 0000000 0000000 00000003666 14043255270 0024517 0 ustar 00root root 0000000 0000000 /**
* \file: bacterium.h
*
* Bacterium alaposztály és leszármazottjai
*/
#ifndef BACTERIUM_H
#define BACTERIUM_H
#include
/// Bacterium osztály.
class Bacterium {
std::string name;
public:
/// @param n - baktérium neve
Bacterium(const char *n = "") : name(n) {}
/// show
/// @param os - adatfolyam amire kiírja a nevét
virtual void show(std::ostream& os) const {
os << "Bakterium " << name;
};
virtual ~Bacterium() {}
};
/// Salmonella osztály.
/// Bacterium virtuális alaposztályból származik
/// a többszörös öröklési úton való elérésből adódó problémák kiküszöbölése miatt.
class Salmonella : virtual public Bacterium {
std::string species; // faj neve
public:
/// @param n - salmonella fajtája
Salmonella(const char *sp) :Bacterium("Salmonella"), species(sp) {}
/// show
/// @param os - adatfolyam amire kiírja a nevét és fajtáját
void show(std::ostream& os) const {
Bacterium::show(os);
os << " Fajta: " << species;
}
};
/// Streptococcus osztály.
/// Bacterium virtuális alaposztályból származik
/// a többszörös öröklési úton való elérésből adódó problémák kiküszöbölése miatt.
class Streptococcus : virtual public Bacterium {
char group; // csoport neve
public:
/// @param n - Streptococus baci csoportja
Streptococcus(char grp) :Bacterium("Streptococcus"), group(grp) {}
/// show
/// @param os - adatfolyam amire kiírja a nevét és csoportját
void show(std::ostream& os) const {
Bacterium::show(os);
os << " Csoport: " << group;
}
};
/// Funktor a kiíráshoz
/// Konstruktor paraméterben megadott adatfolyamra ír
class BacteriumShow {
std::ostream& os;
public:
BacteriumShow(std::ostream& os = std::cout) :os(os) {}
void operator()(Bacterium *p) {
p->show(os);
os << std::endl;
}
};
#endif // BACTERIUM_H
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/clonable.h 0000664 0000000 0000000 00000000461 14043255270 0024311 0 ustar 00root root 0000000 0000000 /**
* \file: clonable.h
*
* Clonable absztrakt osztály
*/
#ifndef CLONABLE_H
#define CLONABLE_H
/// Clonable absztrakt osztály.
struct Clonable {
/// Előállít egy önmagával azonos példányt
virtual Clonable* clone() const = 0;
virtual ~Clonable() {};
};
#endif // CLONABLE_H
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/clonable_bacterium.h 0000664 0000000 0000000 00000001016 14043255270 0026341 0 ustar 00root root 0000000 0000000 /**
* \file: clonable_bacterium.h
*
*/
#ifndef CLONABLE_BACTERIUM_H
#define CLONABLE_BACTERIUM_H
#include "bacterium.h"
#include "clonable.h"
#error "itt készítse el Baktérium osztályok klonozható változatát"
/**
* A ClonableBacterium, ClonableSalmonella, ClonableStreptococcus
* osztályoknak kompatibilisnek kell lennie a Bacterium és Clonable osztályokkal.
* A funkciókat tekintve meg kell egyezni a Bacterium, Salmonella, Streptococcus
* osztályok funkcióival.
*/
#endif // CLONABLE_BACTERIUM_H
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/clonable_hetero_store.hpp 0000664 0000000 0000000 00000000326 14043255270 0027433 0 ustar 00root root 0000000 0000000 /**
* \file: clonable_hetero_store.hpp
*
*/
#ifndef CLONABLE_HETERO_STORE_HPP
#define CLONABLE_HETERO_STORE_HPP
#error "itt készítse el a ClonableHeteroStore sablont"
#endif // CLONABLE_HETERO_STORE_HPP
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/clonable_hetero_test.cpp 0000664 0000000 0000000 00000023641 14043255270 0027256 0 ustar 00root root 0000000 0000000 /**
* \file: clonable_hetero.cpp
*
* Tesztprogram a klónozható heterogén kollekciót tároló
* ClonableHeteroStore osztály működésének ellenőrzéséhez
*
*/
#include
#include
#include
#include "gtest_lite.h"
#include "memtrace.h"
#include "clonable_hetero_store.hpp"
#include "clonable_testclass.h"
#ifdef BACI_IS_VAN
#include "clonable_bacterium.h"
#endif
#include "bacterium.h"
/// Saját kivételosztály az ellenőrzéshez
struct MyException : std::exception {
MyException(...) {}
};
/// Saját fix méretű tároló az ellenőrzéshez.
/// Egyszerű adatper az std::vector-ra.
template
struct fixVec : public std::vector {
void push_back(const T& d) {
if (std::vector::size() >= siz) throw std::bad_alloc();
std::vector::push_back(d);
}
};
int main() {
GTINIT(std::cin); // Csak C(J)PORTA működéséhez kell
/// Csak a méreteket ellenőrizzük
/// Saját tárolóval ellenőrizzük, hogy dob-e kivételt
TEST(Test1, Sanity) {
/// Saját tárolóban csak 2 hely van!
ClonableHeteroStore > t1;
/// Egyben példa az unsigned érték literállal történő összehasonlítására, vagy cast-olunk.
EXPECT_TRUE(0 == t1.size()) << "Nem ures?" << std::endl;
EXPECT_NO_THROW(t1.add(NULL)) << "Nem jo a meret!" << std::endl;
/// Itt cast-olunk
EXPECT_EQ((size_t)1, t1.size());
EXPECT_NO_THROW(t1.add(NULL));
EXPECT_EQ((size_t)2, t1.size()) << "Nem jo a meret!" << std::endl;
EXPECT_THROW(t1.add(NULL), std::out_of_range&);
t1.clear();
EXPECT_EQ((size_t)0, t1.size()) << "Nem torlodott?" << std::endl;
} ENDM
/// Saját tárolóval ellenőrizzük, hogy dob-e SAJÁT kivételt
/// Ellenőrizzük, hogy ha kivételt dob előtte felszabadítja-e, ami nem fért be.
TEST(Test2, Exception) {
/// Saját tárolóban csak 1 hely van !
ClonableHeteroStore, MyException> t1;
EXPECT_NO_THROW(t1.add(new ClonableTestClass));
EXPECT_THROW(t1.add(new ClonableTestClass), MyException&); /// Kivétel esetén fel kell szabadítania
} ENDMsg("Lehet, hogy hiba eseten nem szabaditotta fel a 'tarolora bizott' objektumot?")
/// Megnézzük std::list-el is, ami nem indexelhető
TEST(Test3, List) {
/// Heterogén tárroló stt::list-tel
ClonableHeteroStore > t1;
EXPECT_TRUE(0 == t1.size()) << "Nem ures?" << std::endl;
EXPECT_NO_THROW(t1.add(NULL)) << "Nem jo a meret!" << std::endl;
EXPECT_EQ((size_t)1, t1.size());
EXPECT_NO_THROW(t1.add(NULL));
EXPECT_EQ((size_t)2, t1.size()) << "Nem jo a meret!" << std::endl;
t1.clear(); /// törli a tárolót
EXPECT_EQ((size_t)0, t1.size()) << "Nem torlodott?" << std::endl;
} ENDM
/// Megnézzük, hogy jól működik-e tároló valós objektummal.
/// Megnézzük, hogy van-e esetleg szeletelődés
TEST(Test4, Heterogen) {
/// Default tároló (std::vector-ral)
ClonableHeteroStore t1;
t1.add(new ClonableTestClass1(1));
t1.add(new ClonableTestClass1(2));
t1.add(new ClonableTestClass2("Hello"));
t1.add(new ClonableTestClass2("World"));
t1.add(new ClonableTestClass1(3));
t1.add(new ClonableTestClass2("Bye"));
std::stringstream ss;
TestClassPrint print(ss); /// stringstream-be írunk
std::for_each(t1.begin(), t1.end(), print); /// ez lett a traverse helyett
EXPECT_STREQ("1;2;Hello;World;3;Bye;", ss.str().c_str()) <<
"Valami baj van! Szeletelodes?" << std::endl;
} ENDM
/// Megnézzük, hogy jól működik-e a másoló ctor.
TEST(Test4, Copy) {
ClonableHeteroStore t1; ///
t1.add(new ClonableTestClass1(1));
t1.add(new ClonableTestClass1(2));
t1.add(new ClonableTestClass2("Hello"));
t1.add(new ClonableTestClass2("World"));
t1.add(new ClonableTestClass1(3));
t1.add(new ClonableTestClass2("Bye"));
ClonableHeteroStore t2 = t1;
EXPECT_EQ((size_t)6, t2.size());
std::stringstream ss; /// Ebbe stringstream-be írunk
std::for_each(t2.begin(), t2.end(), TestClassPrint(ss)); /// Funktor létrehozása a paraméterlistán
EXPECT_STREQ("1;2;Hello;World;3;Bye;", ss.str().c_str()) <<
"Valami baj van! Nem jo a masolat!" << std::endl;
/// Csak a pointereket másolta le, vagy az objektumokat is ?
ClonableHeteroStore::const_iterator it1, it2;
for (it1 = t1.begin(), it2 = t2.begin(); it1 != t1.end(); ++it1,++it2)
EXPECT_NE(*it1, *it2) << "Lehet, hogy nem deep copy-t csinalt?" << std::endl;
} ENDM
/// Megnézzük, hogy jól működik-e a az értékadás.
/// Ezt listával próbáljuk.
TEST(Test5, Assign) {
ClonableHeteroStore > t1;
t1.add(new ClonableTestClass1(1));
t1.add(new ClonableTestClass1(2));
t1.add(new ClonableTestClass2("Hello"));
t1.add(new ClonableTestClass2("World"));
t1.add(new ClonableTestClass1(3));
t1.add(new ClonableTestClass2("Bye"));
ClonableHeteroStore > t2;
t2 = t1 = t1;
EXPECT_EQ((size_t)6, t2.size());
std::stringstream ss;
TestClassPrint print(ss); /// stringstrem-be írunk
std::for_each(t2.begin(), t2.end(), print);
EXPECT_STREQ("1;2;Hello;World;3;Bye;", ss.str().c_str()) <<
"Valami baj van! Nem jo a masolat!" << std::endl;
/// Csak a pointereket másolta le, vagy az objektumokat is ?
ClonableHeteroStore >::const_iterator it1, it2;
for (it1 = t1.begin(), it2 = t2.begin(); it1 != t1.end(); ++it1,++it2)
EXPECT_NE(*it1, *it2) << "Lehet, hogy nem deep copy-t csinalt?" << std::endl;
} ENDM
#ifdef BACI_IS_VAN
/// ClonableBacterium osztály működésének vizsgálata
/// Itt még nem klónoz
TEST(Test6, bacterium) {
ClonableHeteroStore petri;
petri.add(new ClonableSalmonella("bongori"));
petri.add(new ClonableStreptococcus('A'));
EXPECT_EQ((size_t)2, petri.size());
std::stringstream ss;
BacteriumShow show(ss); /// stringstrem-be írunk
std::for_each(petri.begin(), petri.end(), show);
EXPECT_STREQ("Bakterium Salmonella Fajta: bongori\n"
"Bakterium Streptococcus Csoport: A\n", ss.str().c_str()) <<
"Valami baj van! Szeletelodes? Virt. alaposztaly konstruktora? " << std::endl;
petri.add(new ClonableSalmonella("enterica"));
petri.add(new ClonableStreptococcus('B'));
std::cout << "petri:\n";
std::for_each(petri.begin(), petri.end(), BacteriumShow()); /// képernyőre írunk
} ENDM
/// Megnézzük, hogy jól működik-e a másoló ctor.
TEST(Test7, bacterium_copy) {
ClonableHeteroStore petri;
petri.add(new ClonableSalmonella("bongori"));
petri.add(new ClonableStreptococcus('A'));
petri.add(new ClonableSalmonella("enterica"));
petri.add(new ClonableStreptococcus('B'));
/// Klónozás jön (másoló ctor)
ClonableHeteroStore agar = petri;
EXPECT_EQ((size_t)4, agar.size());
std::stringstream ss;
std::for_each(agar.begin(), agar.end(), BacteriumShow(ss)); /// Funktor létrehozása a paraméterlistán
EXPECT_STREQ(
"Bakterium Salmonella Fajta: bongori\n"
"Bakterium Streptococcus Csoport: A\n"
"Bakterium Salmonella Fajta: enterica\n"
"Bakterium Streptococcus Csoport: B\n",
ss.str().c_str()) << "Valami baj van! Nem jo a masolat!" << std::endl;
ClonableHeteroStore::const_iterator it1, it2;
for (it1 = petri.begin(), it2 = agar.begin(); it1 != petri.end(); ++it1,++it2)
EXPECT_NE(*it1, *it2) << "Lehet, hogy nem deep copy-t csinalt?" << std::endl;
std::cout << "copy:\n";
std::for_each(agar.begin(), agar.end(), BacteriumShow()); /// képernyőre írunk
} ENDM
TEST(Test8, bacterium_assign) {
ClonableHeteroStore petri;
petri.add(new ClonableSalmonella("bongori"));
petri.add(new ClonableStreptococcus('A'));
petri.add(new ClonableSalmonella("enterica"));
petri.add(new ClonableStreptococcus('B'));
/// Klónozás jön (többszöros értékadás)
ClonableHeteroStore agar;
agar = agar = petri;
EXPECT_EQ((size_t)4, agar.size());
std::stringstream ss;
BacteriumShow show(ss);
std::for_each(agar.begin(), agar.end(), show);
EXPECT_STREQ(
"Bakterium Salmonella Fajta: bongori\n"
"Bakterium Streptococcus Csoport: A\n"
"Bakterium Salmonella Fajta: enterica\n"
"Bakterium Streptococcus Csoport: B\n",
ss.str().c_str()) << "Valami baj van! Nem jo a masolat!" << std::endl;
ClonableHeteroStore::const_iterator it1, it2;
for (it1 = petri.begin(), it2 = agar.begin(); it1 != petri.end(); ++it1,++it2)
EXPECT_NE(*it1, *it2) << "Lehet, hogy nem deep copy-t csinalt?" << std::endl;
std::cout << "assign:\n";
std::for_each(agar.begin(), agar.end(), BacteriumShow());
} ENDM
#endif
/// Itt a vége
GTEND(std::cerr); // Csak C(J)PORTA működéséhez kell
return 0;
}
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/clonable_testclass.h 0000664 0000000 0000000 00000003210 14043255270 0026371 0 ustar 00root root 0000000 0000000 /**
* \file: clonable_testclass.h
*
*/
#ifndef CLONABLE_TESTCLASS_H
#define CLONABLE_TESTCLASS_H
#include "testclass.h"
#include "clonable.h"
/// ClonableTestClass osztály.
/// TestClass-ból hozza a funkcionalitást,
/// a Clonable-ből pedig a klónozhatóságot.
struct ClonableTestClass : virtual TestClass, Clonable {
ClonableTestClass *clone() const { return new ClonableTestClass(*this); }
};
/// ClonableTestClass1 osztály.
/// TestClass1-ből hozza a funkcionalitást,
/// a ClonableTestClass-ból pedig a klónozhatóságot, de ennek és a TestClass1-nek is
/// alaposztálya a TestClass, ami virtuális alap mindkettőben.
struct ClonableTestClass1 : TestClass1, ClonableTestClass {
ClonableTestClass1(int a = 0) :
// az öröklési a lánc végén meg kell hívni a virt. alaposztály konstrukorát
TestClass(), // ez lenne a default, de kiírjuk, hogy látszódjon
TestClass1(a) { }
ClonableTestClass1 *clone() const { return new ClonableTestClass1(*this); }
};
/// ClonableTestClass2 osztály.
/// TestClass2-ből hozza a funkcionalitást,
/// a ClonableTestClass-ból pedig a klónozhatóságot, de ennek és a TestClass2-nek is
/// alaposztálya a TestClass, ami virtuális alap mindkettőben.
struct ClonableTestClass2 : TestClass2, ClonableTestClass {
ClonableTestClass2(std::string s = "") :
// az öröklési a lánc végén meg kell hívni a virt. alaposztály konstrukorát
TestClass(), // ez lenne a default, de kiírjuk, hogy látszódjon
TestClass2(s) {}
ClonableTestClass2 *clone() const { return new ClonableTestClass2(*this); }
};
#endif // CLONABLE_TESTCLASS_H
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/gtest_lite.h 0000664 0000000 0000000 00000046474 14043255270 0024713 0 ustar 00root root 0000000 0000000 #ifndef GTEST_LITE_H
#define GTEST_LITE_H
/**
* \file gtest_lite.h (v3/2019)
*
* Google gtest keretrendszerhez hasonló rendszer.
* Sz.I. 2015., 2016., 2017. (_Has_X)
* Sz.I. 2018 (template), ENDM, ENDMsg, nullptr_t
* Sz.I. 2019 singleton
* Sz.I. 2021 ASSERT.., STRCASE...
* Sz.I. 2021 EXPEXT_REGEXP, CREATE_Has_fn_, cmp w. NULL, EXPECT_ param fix
*
* A tesztelés legalapvetőbb funkcióit támogató függvények és makrók.
* Nem szálbiztos megvalósítás.
*
*
* Szabadon felhasználható, bővíthető.
*
* Használati példa:
* Teszteljük az f(x)=2*x függvényt:
* int f(int x) { return 2*x; }
*
* int main() {
* TEST(TeszEsetNeve, TesztNeve)
* EXPECT_EQ(0, f(0));
* EXPECT_EQ(4, f(2)) << "A függvény hibás eredményt adott" << std::endl;
* ...
* END
* ...
* // Fatális hiba esetén a teszteset nem fut tovább. Ezek az ASSERT... makrók.
* // Nem lehet a kiírásukhoz további üzenetet fűzni. PL:
* TEST(TeszEsetNeve, TesztNeve)
* ASSERT_NO_THROW(f(0)); // itt nem lehet << "duma"
* EXPECT_EQ(4, f(2)) << "A függvény hibás eredményt adott" << std::endl;
* ...
* END
* ...
*
* A működés részleteinek megértése szorgalmi feladat.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#if __cplusplus >= 201103L
# include
# include
#endif
#ifdef MEMTRACE
# include "memtrace.h"
#endif
// Két makró az egyes tesztek elé és mögé:
// A két makró a kapcsos zárójelekkel egy új blokkot hoz létre, amiben
// a nevek lokálisak, így elkerülhető a névütközés.
/// Teszt kezdete. A makró paraméterezése hasonlít a gtest
/// paraméterezéséhez. Így az itt elkészített testek könnyen átemelhetők
/// a gtest keretrendszerbe.
/// @param C - teszteset neve (csak a gtest kompatibilitás miatt van külön neve az eseteknek)
/// @param N - teszt neve
#define TEST(C, N) do { gtest_lite::test.begin(#C"."#N);
/// Teszteset vége.
#define END gtest_lite::test.end(); } while (false);
/// Teszteset vége allokált blokkok számának összehasonlításával
/// Ez az ellenőrzés nem bomba biztos.
#define ENDM gtest_lite::test.end(true); } while (false);
/// Teszteset vége allokált blokkok számának összehasonlításával
/// Ez az ellenőrzés nem bomba biztos.
/// Ha hiba van kiírja az üzenetet.
#define ENDMsg(t) gtest_lite::test.end(true) << t << std::endl; } while (false);
// Eredmények vizsgálatát segítő makrók.
// A paraméterek és a funkciók a gtest keretrendszerrel megegyeznek.
/// Sikeres teszt makrója
#define SUCCEED() gtest_lite::test.expect(true, __FILE__, __LINE__, "SUCCEED()", true)
/// Sikertelen teszt fatális hiba makrója
#define FAIL() gtest_lite::test.expect(false, __FILE__, __LINE__, "FAIL()", true)
/// Sikertelen teszt makrója
#define ADD_FAILURE() gtest_lite::test.expect(false, __FILE__, __LINE__, "ADD_FAILURE()", true)
/// Azonosságot elváró makró
#define EXPECT_EQ(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::eq, __FILE__, __LINE__, "EXPECT_EQ(" #expected ", " #actual ")" )
/// Eltérést elváró makró
#define EXPECT_NE(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::ne, __FILE__, __LINE__, "EXPECT_NE(" #expected ", " #actual ")", "etalon" )
/// Kisebb, vagy egyenlő relációt elváró makró
#define EXPECT_LE(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::le, __FILE__, __LINE__, "EXPECT_LE(" #expected ", " #actual ")", "etalon" )
/// Kisebb, mint relációt elváró makró
#define EXPECT_LT(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::lt, __FILE__, __LINE__, "EXPECT_LT(" #expected ", " #actual ")", "etalon" )
/// Nagyobb, vagy egyenlő relációt elváró makró
#define EXPECT_GE(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::ge, __FILE__, __LINE__, "EXPECT_GE(" #expected ", " #actual ")", "etalon" )
/// Nagyobb, mint relációt elváró makró
#define EXPECT_GT(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::gt, __FILE__, __LINE__, "EXPECT_GT(" #expected ", " #actual ")", "etalon" )
/// Igaz értéket elváró makró
#define EXPECT_TRUE(actual) gtest_lite::EXPECT_(true, actual, gtest_lite::eq, __FILE__, __LINE__, "EXPECT_TRUE(" #actual ")" )
/// Hamis értéket elváró makró
#define EXPECT_FALSE(actual) gtest_lite::EXPECT_(false, actual, gtest_lite::eq, __FILE__, __LINE__, "EXPECT_FALSE(" #actual ")" )
/// Valós számok azonosságát elváró makró
#define EXPECT_FLOAT_EQ(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::almostEQ, __FILE__, __LINE__, "EXPECT_FLOAT_EQ(" #expected ", " #actual ")" )
/// Valós számok azonosságát elváró makró
#define EXPECT_DOUBLE_EQ(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::almostEQ, __FILE__, __LINE__, "EXPECT_DOUBLE_EQ(" #expected ", " #actual ")" )
/// C stringek (const char *) azonosságát tesztelő makró
#define EXPECT_STREQ(expected, actual) gtest_lite::EXPECTSTR(expected, actual, gtest_lite::eqstr, __FILE__, __LINE__, "EXPECT_STREQ(" #expected ", " #actual ")" )
/// C stringek (const char *) eltéréset tesztelő makró
#define EXPECT_STRNE(expected, actual) gtest_lite::EXPECTSTR(expected, actual, gtest_lite::nestr, __FILE__, __LINE__, "EXPECT_STRNE(" #expected ", " #actual ")", "etalon" )
/// C stringek (const char *) azonosságát tesztelő makró (kisbetű/nagybetű azonos)
#define EXPECT_STRCASEEQ(expected, actual) gtest_lite::EXPECTSTR(expected, actual, gtest_lite::eqstrcase, __FILE__, __LINE__, "EXPECT_STRCASEEQ(" #expected ", " #actual ")" )
/// C stringek (const char *) eltéréset tesztelő makró (kisbetű/nagybetű azonos)
#define EXPECT_STRCASENE(expected, actual) gtest_lite::EXPECTSTR(expected, actual, gtest_lite::nestrcase, __FILE__, __LINE__, "EXPECT_STRCASENE(" #expected ", " #actual ")", "etalon" )
/// Kivételt várunk
#define EXPECT_THROW(statement, exception_type) try { gtest_lite::test.tmp = false; statement; } \
catch (exception_type) { gtest_lite::test.tmp = true; } \
catch (...) { } \
EXPECTTHROW(statement, "kivetelt dob.", "nem dobott '"#exception_type"' kivetelt.")
/// Kivételt várunk
#define EXPECT_ANY_THROW(statement) try { gtest_lite::test.tmp = false; statement; } \
catch (...) { gtest_lite::test.tmp = true; } \
EXPECTTHROW(statement, "kivetelt dob.", "nem dobott kivetelt.")
/// Nem várunk kivételt
#define EXPECT_NO_THROW(statement) try { gtest_lite::test.tmp = true; statement; } \
catch (...) { gtest_lite::test.tmp = false; }\
EXPECTTHROW(statement, "nem dob kivetelt.", "kivetelt dobott.")
/// Nem várunk kivételt
#define ASSERT_NO_THROW(statement) try { gtest_lite::test.tmp = true; statement; } \
catch (...) { gtest_lite::test.tmp = false; }\
ASSERTTHROW(statement, "nem dob kivetelt.", "kivetelt dobott.")
/// Kivételt várunk és továbbdobjuk -- ilyen nincs a gtest-ben
#define EXPECT_THROW_THROW(statement, exception_type) try { gtest_lite::test.tmp = false; statement; } \
catch (exception_type) { gtest_lite::test.tmp = true; throw; } \
EXPECTTHROW(statement, "kivetelt dob.", "nem dobott '"#exception_type"' kivetelt.")
/// Környezeti változóhoz hasonlít -- ilyen nincs a gtest-ben
#define EXPECT_ENVEQ(expected, actual) gtest_lite::EXPECTSTR(std::getenv(expected), actual, gtest_lite::eqstr, __FILE__, __LINE__, "EXPECT_ENVEQ(" #expected ", " #actual ")" )
/// Környezeti változóhoz hasonlít -- ilyen nincs a gtest-ben (kisbetű/nagybetű azonos)
#define EXPECT_ENVCASEEQ(expected, actual) gtest_lite::EXPECTSTR(std::getenv(expected), actual, gtest_lite::eqstrcase, __FILE__, __LINE__, "EXPECT_ENVCASEEQ(" #expected ", " #actual ")" )
#if __cplusplus >= 201103L
/// Reguláris kifejezés illesztése
# define EXPECT_REGEXP(expected, actual, match, err) gtest_lite::EXPECTREGEXP(expected, actual, match, err, __FILE__, __LINE__, "EXPECT_REGEXP(" #expected ", " #actual ", " #match ")" )
#endif
////--------------------------------------------------------------------------------------------
/// ASSERT típusú ellenőrzések. CSak 1-2 van megvalósítva. Nem ostream& -val térnek vissza !!!
/// Kivételt várunk
/// Azonosságot elváró makró
#define ASSERT_EQ(expected, actual) gtest_lite::ASSERT_(expected, actual, gtest_lite::eq, "ASSER_EQ")
/// Nem várunk kivételt
#define ASSERT_NO_THROW(statement) try { gtest_lite::test.tmp = true; statement; } \
catch (...) { gtest_lite::test.tmp = false; }\
ASSERTTHROW(statement, "nem dob kivetelt.", "kivetelt dobott.")
/// Segédmakró egy adattag, vagy tagfüggvény létezésének tesztelésére futási időben
/// Ötlet:
/// https://cpptalk.wordpress.com/2009/09/12/substitution-failure-is-not-an-error-2
/// Használat:
/// CREATE_Has_(size)
/// ... if (_Has_size::member)...
#define CREATE_Has_(X) \
template struct _Has_##X { \
struct Fallback { int X; }; \
struct Derived : T, Fallback {}; \
template struct ChT; \
template static char (&f(ChT*))[1]; \
template static char (&f(...))[2]; \
static bool const member = sizeof(f(0)) == 2; \
};
#define CREATE_Has_fn_(X, S) \
template struct _Has_fn_##X##_##S { \
template struct ChT; \
template static char (&f(ChT*))[1]; \
template static char (&f(...))[2]; \
static bool const fn = sizeof(f(0)) == 1; \
};
/// Segédfüggvény egy publikus adattag, vagy tagfüggvény létezésének tesztelésére
/// fordítási időben
inline void hasMember(...) {}
/// Segédsablon típuskonverzió futás közbeni ellenőrzésere
template
struct _Is_Types {
template static char (&f(D))[1];
template static char (&f(...))[2];
static bool const convertable = sizeof(f(F())) == 1;
};
/// -----------------------------------
/// Belső megvalósításhoz tartozó makrók, és osztályok.
/// Nem célszerű közvetlenül használni, vagy módosítani
/// -----------------------------------
/// EXPECTTHROW: kivételkezelés
#define EXPECTTHROW(statement, exp, act) gtest_lite::test.expect(gtest_lite::test.tmp, __FILE__, __LINE__, #statement) \
<< "** Az utasitas " << (act) \
<< "\n** Azt vartuk, hogy " << (exp) << std::endl
#define ASSERTTHROW(statement, exp, act) gtest_lite::test.expect(gtest_lite::test.tmp, __FILE__, __LINE__, #statement) \
<< "** Az utasitas " << (act) \
<< "\n** Azt vartuk, hogy " << (exp) << std::endl; if (!gtest_lite::test.status) { gtest_lite::test.end(); break; }
#define ASSERT_(expected, actual, fn, op) EXPECT_(expected, actual, fn, __FILE__, __LINE__, #op "(" #expected ", " #actual ")" ); \
if (!gtest_lite::test.status) { gtest_lite::test.end(); break; }
#ifdef CPORTA
#define GTINIT(is) \
int magic; \
is >> magic;
#else
#define GTINIT(IS)
#endif // CPORTA
#ifdef CPORTA
#define GTEND(os) \
os << magic << (gtest_lite::test.fail() ? " NO" : " OK?") << std::endl;
#else
#define GTEND(os)
#endif // CPORTA
/// gtest_lite: a keretrendszer függvényinek és objektumainak névtere
namespace gtest_lite {
/// Tesztek állapotát tároló osztály.
/// Egyetlen egy statikus példány keletkezik, aminek a
/// destruktora a futás végén hívódik meg.
struct Test {
int sum; ///< tesztek számlálója
int failed; ///< hibás tesztek
int ablocks; ///< allokált blokkok száma
bool status; ///< éppen futó teszt státusza
bool tmp; ///< temp a kivételkezeléshez;
std::string name; ///< éppen futó teszt neve
std::fstream null; ///< nyelő, ha nem kell kiírni semmit
std::ostream& os; ///< ide írunk
static Test& getTest() {
static Test instance;///< egyedüli (singleton) példány
return instance;
}
private: /// singleton minta miatt
Test() :sum(0), failed(0), status(false), null("/dev/null"), os(std::cout) {}
Test(const Test&);
void operator=(const Test&);
public:
/// Teszt kezdete
void begin(const char *n) {
name = n; status = true;
#ifdef MEMTRACE
ablocks = memtrace::allocated_blocks();
#endif
os << "\n---> " << name << std::endl;
++sum;
}
/// Teszt vége
std::ostream& end(bool memchk = false) {
#ifdef MEMTRACE
if (memchk && ablocks != memtrace::allocated_blocks()) {
status = false;
return os << "** Lehet, hogy nem szabaditott fel minden memoriat! **" << std::endl;
}
#endif
os << (status ? " SIKERES" : "** HIBAS ****") << "\t" << name << " <---" << std::endl;
#ifdef CPORTA
if (!status)
std::cerr << (status ? " SIKERES" : "** HIBAS ****") << "\t" << name << " <---" << std::endl;
#endif // CPORTA
if (!status)
return os;
else
return null;
}
bool fail() { return failed; }
bool astatus() { return status; }
/// Eredményt adminisztráló tagfüggvény True a jó eset.
std::ostream& expect(bool st, const char *file, int line, const char *expr, bool pr = false) {
if (!st) {
++failed;
status = false;
}
if (!st || pr) {
std::string str(file);
size_t i = str.rfind("\\");
if (i == std::string::npos) i = str.rfind("/");
if (i == std::string::npos) i = 0; else i++;
return os << "\n**** " << &file[i] << "(" << line << "): " << expr << " ****" << std::endl;
}
return null;
}
/// Destruktor
~Test() {
if (sum != 0) {
os << "\n==== TESZT VEGE ==== HIBAS/OSSZES: " << failed << "/" << sum << std::endl;
#ifdef CPORTA
if (failed)
std::cerr << "\n==== TESZT VEGE ==== HIBAS/OSSZES: " << failed << "/" << sum << std::endl;
#endif // CPORTA
}
}
};
/// A statikus referencia minden fordítási egységben keletkezik, de
/// mindegyik egyetlen példányra fog hivatkozni a singleton minta miatt
static Test& test = Test::getTest();
/// általános sablon a várt értékhez.
template
std::ostream& EXPECT_(T1 exp, T2 act, bool (*pred)(T1, T1), const char *file, int line,
const char *expr, const char *lhs = "elvart", const char *rhs = "aktual") {
return test.expect(pred(exp, act), file, line, expr)
<< "** " << lhs << ": " << std::boolalpha << exp
<< "\n** " << rhs << ": " << std::boolalpha << act << std::endl;
}
/// pointerre specializált sablon a várt értékhez.
template
std::ostream& EXPECT_(T1* exp, T2* act, bool (*pred)(T1*, T1*), const char *file, int line,
const char *expr, const char *lhs = "elvart", const char *rhs = "aktual") {
return test.expect(pred(exp, act), file, line, expr)
<< "** " << lhs << ": " << (void*) exp
<< "\n** " << rhs << ": " << (void*) act << std::endl;
}
#if __cplusplus >= 201103L
/// nullptr-re specializált sablon a várt értékhez.
template
std::ostream& EXPECT_(std::nullptr_t exp, T* act, bool (*pred)(T*, T*), const char *file, int line,
const char *expr, const char *lhs = "elvart", const char *rhs = "aktual") {
return test.expect(pred(exp, act), file, line, expr)
<< "** " << lhs << ": " << (void*) exp
<< "\n** " << rhs << ": " << (void*) act << std::endl;
}
template
std::ostream& EXPECT_(T* exp, std::nullptr_t act, bool (*pred)(T*, T*), const char *file, int line,
const char *expr, const char *lhs = "elvart", const char *rhs = "aktual") {
return test.expect(pred(exp, act), file, line, expr)
<< "** " << lhs << ": " << (void*) exp
<< "\n** " << rhs << ": " << (void*) act << std::endl;
}
#endif
/// stringek összehasonlításához.
/// azért nem spec. mert a sima EQ-ra másként kell működnie.
inline
std::ostream& EXPECTSTR(const char *exp, const char *act, bool (*pred)(const char*, const char*), const char *file, int line,
const char *expr, const char *lhs = "elvart", const char *rhs = "aktual") {
return test.expect(pred(exp, act), file, line, expr)
<< "** " << lhs << ": " << (exp == NULL ? "NULL pointer" : std::string("\"") + exp + std::string("\""))
<< "\n** " << rhs << ": " << (act == NULL ? "NULL pointer" : std::string("\"") + act + std::string("\"")) << std::endl;
}
#if __cplusplus >= 201103L
/// regexp összehasonlításhoz.
template
int count_regexp(E exp, S str) {
std::regex rexp(exp);
auto w_beg = std::sregex_iterator(str.begin(), str.end(), rexp);
auto w_end = std::sregex_iterator();
return std::distance(w_beg, w_end);
}
template
std::ostream& EXPECTREGEXP(E exp, S str, int match, const char *err, const char *file, int line,
const char *expr, const char *lhs = "regexp", const char *rhs = "string",
const char *m = "elvart/illeszkedik") {
int cnt = count_regexp(exp, str);
if (match < 0) match = cnt;
return test.expect(cnt == match, file, line, expr)
<< "** " << lhs << ": " << std::string("\"") + exp + std::string("\"")
<< "\n** " << rhs << ": " << (err == NULL ? std::string("\"") + str + std::string("\"") : err)
<< "\n** " << m << ": " << match << "/" << cnt << std::endl;
}
#endif
/// segéd sablonok a relációkhoz.
/// azért nem STL (algorithm), mert csak a függvény lehet, hogy menjen a deduckció
template
bool eq(T a, T b) { return a == b; }
inline
bool eqstr(const char *a, const char *b) {
if (a != NULL && b != NULL)
return strcmp(a, b) == 0;
return false;
}
inline
bool eqstrcase(const char *a, const char *b) {
if (a != NULL && b != NULL) {
while (toupper(*a) == toupper(*b) && *a != '\0') {
a++;
b++;
}
return *a == *b;
}
return false;
}
template
bool ne(T a, T b) { return a != b; }
inline
bool nestr(const char *a, const char *b) {
if (a != NULL && b != NULL)
return strcmp(a, b) != 0;
return false;
}
template
bool le(T a, T b) { return a <= b; }
template
bool lt(T a, T b) { return a < b; }
template
bool ge(T a, T b) { return a >= b; }
template
bool gt(T a, T b) { return a > b; }
/// Segédsablon valós számok összehasonlításához
/// Nem bombabiztos, de nekünk most jó lesz
/// Elméleti hátér:
/// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
template
bool almostEQ(T a, T b) {
// eps: ha a relatív, vagy abszolút hiba ettől kisebb, akkor elfogadjuk
T eps = 10 * std::numeric_limits::epsilon(); // 10-szer a legkisebb érték
if (a == b) return true;
if (fabs(a - b) < eps)
return true;
double aa = fabs(a);
double ba = fabs(b);
if (aa < ba) {
aa = ba;
ba = fabs(a);
}
return (aa - ba) < aa * eps;
}
/// Segédsablon ostream átirányításához
/// A destruktor visszaállít
class ostreamRedir {
std::ostream& src;
std::streambuf *const save;
public:
ostreamRedir(std::ostream& src, std::ostream& dst)
: src(src), save(src.rdbuf(dst.rdbuf())) {}
~ostreamRedir() { src.rdbuf(save); }
};
} // namespace gtest_lite
#endif // GTEST_LITE_H
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/memtrace.cpp 0000664 0000000 0000000 00000035345 14043255270 0024673 0 ustar 00root root 0000000 0000000 /*********************************
Memoriaszivargas-detektor
Keszitette: Peregi Tamas, BME IIT, 2011
petamas@iit.bme.hu
Kanari: Szeberenyi Imre, 2013.
VS 2012: Szeberényi Imre, 2015.,
mem_dump: 2016.
memset felszabaditaskor: 2018.
typo: 2019.
poi_check: 2021.
*********************************/
/*definialni kell, ha nem paracssorbol allitjuk be (-DMEMTRACE) */
/*#define MEMTRACE */
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include
#include
#include
#include
#include
#ifdef MEMTRACE
#define FROM_MEMTRACE_CPP
#include "memtrace.h"
#define FMALLOC 0
#define FCALLOC 1
#define FREALLOC 2
#define FFREE 3
#define FNEW 4
#define FDELETE 5
#define FNEWARR 6
#define FDELETEARR 7
#define COMP(a,d) (((a)<=3 && (d)<=3) || ((d)==(a)+1))
#define PU(p) ((char*)p+CANARY_LEN) // mem pointerbol user poi
#define P(pu) ((char*)pu-CANARY_LEN) // user pointerbol mem poi
#define XSTR(s) STR(s)
#define STR(s) #s
/*******************************************************************/
/* Segedfuggvenyek es egyebek */
/*******************************************************************/
START_NAMESPACE
static FILE *fperror;
#ifdef MEMTRACE_TO_MEMORY
static const unsigned int CANARY_LEN = 64;
#else
static const unsigned int CANARY_LEN = 0;
#endif
static const unsigned char canary_byte1 = 'k';
static const unsigned char canary_byte2 = 'K';
static unsigned char random_byte;
typedef enum {FALSE,TRUE} BOOL;
static const char * pretty[] = {"malloc(", "calloc(", "realloc(", "free(",
"new", "delete", "new[]", "delete[]"};
static const char * basename(const char * s) {
const char *s1,*s2;
s1 = strrchr(s,'/');
if(s1==NULL) s1 = s; else s1++;
s2 = strrchr(s1, '\\');
if(s2==NULL) s2 = s1; else s2++;
return s2;
}
static char *StrCpy(char ** to, const char * from) {
if(from == NULL) {
*to = NULL;
} else {
*to = (char*)malloc(strlen(from)+1);
if(*to) strcpy(*to, from);
}
return *to;
}
static void *canary_malloc(size_t size, unsigned char data) {
char *p = (char *)malloc(size+2*CANARY_LEN);
if (p) {
memset(p, canary_byte1, CANARY_LEN);
memset(p+CANARY_LEN, data, size);
memset(p+CANARY_LEN+size, canary_byte2, CANARY_LEN);
}
return p;
}
static int chk_canary(void *p, size_t size) {
unsigned char *pc = (unsigned char*)p;
unsigned int i;
for (i = 0; i < CANARY_LEN; i++)
if (pc[i] != canary_byte1)
return -1;
pc += CANARY_LEN+size;
for (i = 0; i < CANARY_LEN; i++)
if (pc[i] != canary_byte2)
return 1;
return 0;
}
typedef struct {
int f; /* allocator func */
int line;
char * par_txt;
char * file;
} call_t;
static call_t pack(int f, const char * par_txt, int line, const char * file) {
call_t ret;
ret.f = f;
ret.line = line;
StrCpy(&ret.par_txt, par_txt);
StrCpy(&ret.file, file);
return ret;
}
static void print_call(const char * msg, call_t call) {
if(msg) fprintf(fperror, "%s", msg);
fprintf(fperror, "%s", pretty[call.f]);
fprintf(fperror, "%s", call.par_txt ? call.par_txt : "?");
if (call.f <= 3) fprintf(fperror, ")");
fprintf(fperror," @ %s:", call.file ? basename(call.file) : "?");
fprintf(fperror,"%d\n",call.line ? call.line : 0);
}
/* memoriateruletet dump */
static void dump_memory(void const *mem, size_t size, size_t can_len, FILE* fp) {
unsigned char const *m=(unsigned char const *) mem;
unsigned int s, o;
if (can_len > 0)
fprintf(fp, "Dump (addr: %p kanari hossz: %d):\n", m+can_len, (int)can_len);
else
fprintf(fp, "Dump: (addr: %p) \n", m);
size += 2*can_len;
for (s = 0; s < (size+15)/16; s++) {
fprintf(fp, "%04x:%c ", s*16, s*16 < can_len || s*16 >= size-can_len ? ' ' : '*');
for (o = 0; o < 16; o++) {
if (o == 8) fprintf(fp, " ");
if (s*16+o < size)
fprintf(fp, "%02x ", m[s*16+o]);
else
fprintf(fp, " ");
}
fprintf(fp, " ");
for (o = 0; o < 16; o++) {
if (s*16+o < size)
fprintf(fp, "%c", isprint(m[s*16+o]) ? m[s*16+o] : '.');
else
fprintf(fp, " ");
}
fprintf(fp, "\n");
}
}
void mem_dump(void const *mem, size_t size, FILE* fp) {
dump_memory(mem, size, 0, fp);
}
static BOOL dying;
static void die(const char * msg, void * p, size_t size, call_t * a, call_t * d) {
#ifdef MEMTRACE_ERRFILE
fperror = fopen(XSTR(MEMTRACE_ERRFILE), "w");
#endif
fprintf(fperror,"%s\n",msg);
if (p) {
fprintf(fperror, "\tPointer:\t%p", PU(p));
if (size) fprintf(fperror," (%d byte)", (int)size);
fprintf(fperror,"\n");
}
if (a) print_call("\tFoglalas:\t", *a);
if (d) print_call("\tFelszabaditas:\t", *d);
if (p) dump_memory(p, size, CANARY_LEN, fperror);
dying = TRUE;
exit(120);
}
static void initialize();
END_NAMESPACE
/*******************************************************************/
/* MEMTRACE_TO_MEMORY */
/*******************************************************************/
#ifdef MEMTRACE_TO_MEMORY
START_NAMESPACE
typedef struct _registry_item {
void * p; /* mem pointer*/
size_t size; /* size*/
call_t call;
struct _registry_item * next;
} registry_item;
static registry_item registry; /*sentinel*/
static registry_item *find_registry_item(void * p) {
registry_item *n = ®istry;
for(; n->next && n->next->p != p ; n=n->next);
return n;
}
static void print_registry_item(registry_item * p) {
if (p) {
print_registry_item(p->next);
fprintf(fperror, "\t%p%5d byte ",p->p, (int)p->size);
print_call(NULL, p->call);
if(p->call.par_txt) free(p->call.par_txt);
if(p->call.file) free(p->call.file);
free(p);
}
}
/* ha nincs hiba, akkor 0-val tér vissza */
int mem_check(void) {
initialize();
if(dying) return 2; /* címzési hiba */
if(registry.next) {
/*szivarog*/
#ifdef MEMTRACE_ERRFILE
fperror = fopen(XSTR(MEMTRACE_ERRFILE), "w");
#endif
fprintf(fperror, "Szivargas:\n");
print_registry_item(registry.next);
registry.next = NULL;
return 1; /* memória fogyás */
}
return 0;
}
/* Ellenorzi, hogy a pointer regisztralt-e. Ha nem, akkor 0-val tér vissza */
int poi_check(void *pu) {
if (pu == NULL) return 1;
initialize();
return find_registry_item(P(pu))->next != NULL;
}
END_NAMESPACE
#endif/*MEMTRACE_TO_MEMORY*/
/*******************************************************************/
/* MEMTRACE_TO_FILE */
/*******************************************************************/
#ifdef MEMTRACE_TO_FILE
START_NAMESPACE
static FILE * trace_file;
END_NAMESPACE
#endif
/*******************************************************************/
/* register/unregister */
/*******************************************************************/
START_NAMESPACE
static int allocated_blks;
int allocated_blocks() { return allocated_blks; }
static BOOL register_memory(void * p, size_t size, call_t call) {
initialize();
allocated_blks++;
#ifdef MEMTRACE_TO_FILE
fprintf(trace_file, "%p\t%d\t%s%s", PU(p), (int)size, pretty[call.f], call.par_txt ? call.par_txt : "?");
if (call.f <= 3) fprintf(trace_file, ")");
fprintf(trace_file, "\t%d\t%s\n", call.line, call.file ? call.file : "?");
fflush(trace_file);
#endif
#ifdef MEMTRACE_TO_MEMORY
{/*C-blokk*/
registry_item * n = (registry_item*)malloc(sizeof(registry_item));
if(n==NULL) return FALSE;
n->p = p;
n->size = size;
n->call = call;
n->next = registry.next;
registry.next = n;
}/*C-blokk*/
#endif
return TRUE;
}
static void unregister_memory(void * p, call_t call) {
initialize();
#ifdef MEMTRACE_TO_FILE
fprintf(trace_file, "%p\t%d\t%s%s", PU(p), -1, pretty[call.f], call.par_txt ? call.par_txt : "?");
if (call.f <= 3) fprintf(trace_file, ")");
fprintf(trace_file,"\t%d\t%s\n",call.line, call.file ? call.file : "?");
fflush(trace_file);
#endif
#ifdef MEMTRACE_TO_MEMORY
{ /*C-blokk*/
registry_item * n = find_registry_item(p);
if(n->next) {
allocated_blks--;
registry_item * r = n->next;
n->next = r->next;
if(COMP(r->call.f,call.f)) {
int chk = chk_canary(r->p, r->size);
if (chk < 0)
die("Blokk elott serult a memoria:", r->p,r->size,&r->call,&call);
if (chk > 0)
die("Blokk utan serult a memoria", r->p,r->size,&r->call,&call);
/*rendben van minden*/
if(call.par_txt) free(call.par_txt);
if(r->call.par_txt) free(r->call.par_txt);
if(call.file) free(call.file);
if(r->call.file) free(r->call.file);
memset(PU(r->p), 'f', r->size);
PU(r->p)[r->size-1] = 0;
free(r);
} else {
/*hibas felszabaditas*/
die("Hibas felszabaditas:",r->p,r->size,&r->call,&call);
}
} else {
die("Nem letezo, vagy mar felszabaditott adat felszabaditasa:", p, 0,NULL,&call);
}
} /*C-blokk*/
#endif
}
END_NAMESPACE
/*******************************************************************/
/* C-stílusú memóriakezelés */
/*******************************************************************/
#ifdef MEMTRACE_C
START_NAMESPACE
void * traced_malloc(size_t size, const char * par_txt, int line, const char * file) {
void * p;
initialize();
p = canary_malloc(size, random_byte);
if (p) {
if(!register_memory(p,size,pack(FMALLOC,par_txt,line,file))) {
free(p);
return NULL;
}
return PU(p);
}
return NULL;
}
void * traced_calloc(size_t count, size_t size, const char * par_txt, int line, const char * file) {
void * p;
initialize();
size *= count;
p = canary_malloc(size, 0);
if(p) {
if(!register_memory(p,size,pack(FCALLOC,par_txt,line,file))) {
free(p);
return NULL;
}
return PU(p);
}
return NULL;
}
void traced_free(void * pu, const char * par_txt, int line, const char * file) {
initialize();
if(pu) {
unregister_memory(P(pu), pack(FFREE,par_txt,line,file));
free(P(pu));
} else {
/*free(NULL) eset*/
#ifdef MEMTRACE_TO_FILE
fprintf(trace_file,"%s\t%d\t%10s\t","NULL",-1,pretty[FFREE]);
fprintf(trace_file,"%d\t%s\n",line,file ? file : "?");
fflush(trace_file);
#endif
#ifndef ALLOW_FREE_NULL
{/*C-blokk*/
call_t call;
call = pack(FFREE,par_txt,line,file);
die("free(NULL) hivasa:",NULL,0,NULL,&call);
}/*C-blokk*/
#endif
}
}
void * traced_realloc(void * old, size_t size, const char * par_txt, int line, const char * file) {
void * p;
size_t oldsize = 0;
registry_item * n;
initialize();
#ifdef MEMTRACE_TO_MEMORY
n = find_registry_item(P(old));
if (n) oldsize = n->next->size;
p = canary_malloc(size, random_byte);
#else
p = realloc(old, size);
#endif
if (p) {
/*Ha sikerult a foglalas, regisztraljuk*/
register_memory(p,size,pack(FREALLOC, par_txt, line,file));
if (old) {
#ifdef MEMTRACE_TO_MEMORY
int cpsize = 2*CANARY_LEN;
if (oldsize < size) cpsize += oldsize;
else cpsize += size;
memcpy(p, P(old), cpsize);
#endif
unregister_memory(P(old), pack(FREALLOC, par_txt, line, file));
#ifdef MEMTRACE_TO_MEMORY
free P(old);
#endif
}
return PU(p);
} else {
return NULL;
}
}
END_NAMESPACE
#endif/*MEMTRACE_C*/
/*******************************************************************/
/* C++-stílusú memóriakezelés */
/*******************************************************************/
#ifdef MEMTRACE_CPP
START_NAMESPACE
std::new_handler _new_handler;
void _set_new_handler(std::new_handler h) {
initialize();
_new_handler = h;
}
static call_t delete_call;
static BOOL delete_called;
void set_delete_call(int line, const char * file) {
initialize();
delete_call=pack(0,"",line,file); /*func értéke lényegtelen, majd felülírjuk*/
delete_called = TRUE;
}
void * traced_new(size_t size, int line, const char * file, int func) {
initialize();
for (;;) {
void * p = canary_malloc(size, random_byte);
if(p) {
register_memory(p,size,pack(func,"",line,file));
return PU(p);
}
if (_new_handler == 0)
throw std::bad_alloc();
_new_handler();
}
}
void traced_delete(void * pu, int func) {
initialize();
if(pu) {
/*kiolvasom call-t, ha van*/
memtrace::call_t call = delete_called ? (delete_call.f=func, delete_call) : pack(func,NULL,0,NULL);
memtrace::unregister_memory(P(pu),call);
free(P(pu));
}
delete_called=FALSE;
}
END_NAMESPACE
void * operator new(size_t size, int line, const char * file) THROW_BADALLOC {
return memtrace::traced_new(size,line,file,FNEW);
}
void * operator new[](size_t size, int line, const char * file) THROW_BADALLOC {
return memtrace::traced_new(size,line,file,FNEWARR);
}
void * operator new(size_t size) THROW_BADALLOC {
return memtrace::traced_new(size,0,NULL,FNEW);
}
void * operator new[](size_t size) THROW_BADALLOC {
return memtrace::traced_new(size,0,NULL,FNEWARR);
}
void operator delete(void * p) THROW_NOTHING {
memtrace::traced_delete(p,FDELETE);
}
void operator delete[](void * p) THROW_NOTHING {
memtrace::traced_delete(p,FDELETEARR);
}
#if __cplusplus >= 201402L
void operator delete(void * p, size_t) THROW_NOTHING {
memtrace::traced_delete(p,FDELETE);
}
void operator delete[](void * p, size_t) THROW_NOTHING {
memtrace::traced_delete(p,FDELETEARR);
}
#endif
/* Visual C++ 2012 miatt kell, mert háklis, hogy nincs megfelelő delete, bár senki sem használja */
void operator delete(void * p, int, const char *) THROW_NOTHING {
memtrace::traced_delete(p,FDELETE);
}
void operator delete[](void * p, int, const char *) THROW_NOTHING {
memtrace::traced_delete(p,FDELETE);
}
#endif/*MEMTRACE_CPP*/
/*******************************************************************/
/* initialize */
/*******************************************************************/
START_NAMESPACE
static void initialize() {
static BOOL first = TRUE;
if(first) {
fperror = stderr;
random_byte = (unsigned char)time(NULL);
first = FALSE;
dying = FALSE;
#ifdef MEMTRACE_TO_MEMORY
registry.next = NULL;
#if !defined(USE_ATEXIT_OBJECT) && defined(MEMTRACE_AUTO)
atexit((void(*)(void))mem_check);
#endif
#endif
#ifdef MEMTRACE_TO_FILE
trace_file = fopen("memtrace.dump","w");
#endif
#ifdef MEMTRACE_CPP
_new_handler = NULL;
delete_called = FALSE;
delete_call = pack(0,NULL,0,NULL);
#endif
}
}
#if defined(MEMTRACE_TO_MEMORY) && defined(USE_ATEXIT_OBJECT)
int atexit_class::counter = 0;
int atexit_class::err = 0;
#endif
END_NAMESPACE
#endif
ClonableHetero-master-4e53476f5a5ea3615ba8b4c163312b69b2812503/memtrace.h 0000664 0000000 0000000 00000014262 14043255270 0024333 0 ustar 00root root 0000000 0000000 /*********************************
Memoriaszivargas-detektor
Keszitette: Peregi Tamas, BME IIT, 2011
petamas@iit.bme.hu
Kanari: Szeberenyi Imre, 2013.,
VS 2012: Szeberényi Imre, 2015.,
mem_dump: 2016.
inclue-ok: 2017., 2018., 2019., 2021.
*********************************/
#ifndef MEMTRACE_H
#define MEMTRACE_H
#if defined(MEMTRACE)
/*ha definiálva van, akkor a hibakat ebbe a fajlba írja, egyébkent stderr-re*/
/*#define MEMTRACE_ERRFILE MEMTRACE.ERR*/
/*ha definialva van, akkor futas kozben lancolt listat epit. Javasolt a hasznalata*/
#define MEMTRACE_TO_MEMORY
/*ha definialva van, akkor futas kozben fajlba irja a foglalasokat*/
/*ekkor nincs ellenorzes, csak naplozas*/
/*#define MEMTRACE_TO_FILE*/
/*ha definialva van, akkor a megallaskor automatikus riport keszul */
#define MEMTRACE_AUTO
/*ha definialva van, akkor malloc()/calloc()/realloc()/free() kovetve lesz*/
#define MEMTRACE_C
#ifdef MEMTRACE_C
/*ha definialva van, akkor free(NULL) nem okoz hibat*/
#define ALLOW_FREE_NULL
#endif
#ifdef __cplusplus
/*ha definialva van, akkor new/delete/new[]/delete[] kovetve lesz*/
#define MEMTRACE_CPP
#endif
#if defined(__cplusplus) && defined(MEMTRACE_TO_MEMORY)
/*ha definialva van, akkor atexit helyett objektumot hasznal*/
/*ajanlott bekapcsolni*/
#define USE_ATEXIT_OBJECT
#endif
/******************************************/
/* INNEN NE MODOSITSD */
/******************************************/
#ifdef NO_MEMTRACE_TO_FILE
#undef MEMTRACE_TO_FILE
#endif
#ifdef NO_MEMTRACE_TO_MEMORY
#undef MEMTRACE_TO_MEMORY
#endif
#ifndef MEMTRACE_AUTO
#undef USE_ATEXIT_OBJECT
#endif
#ifdef __cplusplus
#define START_NAMESPACE namespace memtrace {
#define END_NAMESPACE } /*namespace*/
#define TRACEC(func) memtrace::func
#include
#else
#define START_NAMESPACE
#define END_NAMESPACE
#define TRACEC(func) func
#endif
// THROW deklaráció változatai
#if defined(_MSC_VER)
// VS rosszul kezeli az __cplusplus makrot
#if _MSC_VER < 1900
// * nem biztos, hogy jó így *
#define THROW_BADALLOC
#define THROW_NOTHING
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#else
#if __cplusplus < 201103L
// C++2003 vagy régebbi
#define THROW_BADALLOC throw (std::bad_alloc)
#define THROW_NOTHING throw ()
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#endif
START_NAMESPACE
int allocated_blocks();
END_NAMESPACE
#if defined(MEMTRACE_TO_MEMORY)
START_NAMESPACE
int mem_check(void);
int poi_check(void*);
END_NAMESPACE
#endif
#if defined(MEMTRACE_TO_MEMORY) && defined(USE_ATEXIT_OBJECT)
#include
START_NAMESPACE
class atexit_class {
private:
static int counter;
static int err;
public:
atexit_class() {
#if defined(CPORTA) && !defined(CPORTA_NOSETBUF)
if (counter == 0) {
setbuf(stdout, 0);
setbuf(stderr, 0);
}
#endif
counter++;
}
int check() {
if(--counter == 0)
err = mem_check();
return err;
}
~atexit_class() {
check();
}
};
static atexit_class atexit_obj;
END_NAMESPACE
#endif/*MEMTRACE_TO_MEMORY && USE_ATEXIT_OBJECT*/
/*Innentol csak a "normal" include eseten kell, kulonben osszezavarja a mukodest*/
#ifndef FROM_MEMTRACE_CPP
#include
#ifdef __cplusplus
#include
/* ide gyűjtjük a nemtrace-vel összeakadó headereket, hogy előbb legyenek */
#include // VS 2013 headerjében van deleted definició
#include
#include
#include
#include