Merge pull request #33 from scharlton2/32-memory-leak-in-selected_output

Closes #32 Selected Output Memory Leak
This commit is contained in:
Charlton, Scott R 2023-08-26 18:58:42 -06:00 committed by GitHub
commit 8beb102d54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 167 additions and 45 deletions

View File

@ -153,3 +153,19 @@ size_t FileTest::Size(void)
{ {
return ::FileSize(_fn.c_str()); return ::FileSize(_fn.c_str());
} }
size_t FileTest::LineCount(void)
{
size_t nlines = 0;
if (::FileExists(_fn.c_str()))
{
std::ifstream ifs(_fn.c_str(), std::ifstream::in);
std::string line;
while (std::getline(ifs, line))
{
++nlines;
}
ifs.close();
}
return nlines;
}

View File

@ -25,6 +25,7 @@ public:
bool Exists(void); bool Exists(void);
int Delete(void); int Delete(void);
size_t Size(void); size_t Size(void);
size_t LineCount(void);
protected: protected:
std::string _fn; std::string _fn;

View File

@ -614,11 +614,11 @@ TEST(TestIPhreeqc, TestRunString)
ASSERT_EQ(false, ::FileExists(OUTPUT_FILE)); ASSERT_EQ(false, ::FileExists(OUTPUT_FILE));
ASSERT_EQ(0, obj.LoadDatabase("phreeqc.dat")); ASSERT_EQ(0, obj.LoadDatabase("phreeqc.dat"));
obj.SetOutputFileOn(1); obj.SetOutputFileOn(true);
obj.SetErrorFileOn(0); obj.SetErrorFileOn(false);
obj.SetLogFileOn(0); obj.SetLogFileOn(false);
obj.SetSelectedOutputFileOn(0); obj.SetSelectedOutputFileOn(false);
obj.SetDumpFileOn(0); obj.SetDumpFileOn(false);
ASSERT_EQ(false, ::FileExists(OUTPUT_FILE)); ASSERT_EQ(false, ::FileExists(OUTPUT_FILE));
ASSERT_EQ(0, obj.RunString(input)); ASSERT_EQ(0, obj.RunString(input));
@ -662,11 +662,11 @@ TEST(TestIPhreeqc, TestGetSelectedOutputValue)
ASSERT_EQ(VR_OK, EQUILIBRIUM_PHASES(obj, "calcite", 0.0, 0.010)); ASSERT_EQ(VR_OK, EQUILIBRIUM_PHASES(obj, "calcite", 0.0, 0.010));
ASSERT_EQ(VR_OK, USER_PUNCH(obj, "Ca", max)); ASSERT_EQ(VR_OK, USER_PUNCH(obj, "Ca", max));
obj.SetOutputFileOn(0); obj.SetOutputFileOn(false);
obj.SetErrorFileOn(0); obj.SetErrorFileOn(false);
obj.SetLogFileOn(0); obj.SetLogFileOn(false);
obj.SetSelectedOutputFileOn(0); obj.SetSelectedOutputFileOn(false);
obj.SetDumpFileOn(0); obj.SetDumpFileOn(false);
ASSERT_EQ(0, obj.RunAccumulated()); ASSERT_EQ(0, obj.RunAccumulated());
/* /*
@ -1799,11 +1799,11 @@ TEST(TestIPhreeqc, TestLongHeadings)
// COMMENT: {10/30/2013 10:39:40 PM} ASSERT_EQ( VR_OK, obj.AccumulateLine(oss.str().c_str()) ); // COMMENT: {10/30/2013 10:39:40 PM} ASSERT_EQ( VR_OK, obj.AccumulateLine(oss.str().c_str()) );
// COMMENT: {10/30/2013 10:39:40 PM} //}} // COMMENT: {10/30/2013 10:39:40 PM} //}}
obj.SetOutputFileOn(0); obj.SetOutputFileOn(false);
obj.SetErrorFileOn(0); obj.SetErrorFileOn(false);
obj.SetLogFileOn(0); obj.SetLogFileOn(false);
obj.SetSelectedOutputFileOn(0); obj.SetSelectedOutputFileOn(false);
obj.SetDumpFileOn(0); obj.SetDumpFileOn(false);
ASSERT_EQ(0, obj.RunAccumulated()); ASSERT_EQ(0, obj.RunAccumulated());
ASSERT_EQ(2, obj.GetSelectedOutputRowCount()); ASSERT_EQ(2, obj.GetSelectedOutputRowCount());
@ -1866,12 +1866,12 @@ TEST(TestIPhreeqc, TestDumpString)
ASSERT_EQ(VR_OK, DUMP(obj)); ASSERT_EQ(VR_OK, DUMP(obj));
// run // run
obj.SetOutputFileOn(0); obj.SetOutputFileOn(false);
obj.SetErrorFileOn(0); obj.SetErrorFileOn(false);
obj.SetLogFileOn(0); obj.SetLogFileOn(false);
obj.SetSelectedOutputFileOn(0); obj.SetSelectedOutputFileOn(false);
obj.SetDumpFileOn(0); obj.SetDumpFileOn(false);
obj.SetDumpStringOn(1); obj.SetDumpStringOn(true);
ASSERT_EQ(0, obj.RunAccumulated()); ASSERT_EQ(0, obj.RunAccumulated());
const char* dump_str = obj.GetDumpString(); const char* dump_str = obj.GetDumpString();
@ -3107,7 +3107,7 @@ TEST(TestIPhreeqc, TestSetSelectedOutputFileName)
ASSERT_EQ(false, obj.GetDumpFileOn()); ASSERT_EQ(false, obj.GetDumpFileOn());
ASSERT_EQ(false, obj.GetDumpStringOn()); ASSERT_EQ(false, obj.GetDumpStringOn());
obj.SetSelectedOutputFileOn(1); obj.SetSelectedOutputFileOn(true);
obj.SetSelectedOutputFileName(SELOUT_FILENAME); obj.SetSelectedOutputFileName(SELOUT_FILENAME);
ASSERT_EQ(0, obj.RunAccumulated()); ASSERT_EQ(0, obj.RunAccumulated());
@ -3249,14 +3249,124 @@ TEST(TestIPhreeqc, TestGetSelectedOutputStringLineCount)
ASSERT_EQ(false, obj.GetDumpFileOn()); ASSERT_EQ(false, obj.GetDumpFileOn());
ASSERT_EQ(false, obj.GetDumpStringOn()); ASSERT_EQ(false, obj.GetDumpStringOn());
ASSERT_EQ(false, obj.GetSelectedOutputStringOn() != 0); ASSERT_EQ(false, obj.GetSelectedOutputStringOn());
obj.SetSelectedOutputStringOn(true); obj.SetSelectedOutputStringOn(true);
ASSERT_EQ(true, obj.GetSelectedOutputStringOn());
ASSERT_EQ(0, obj.RunAccumulated()); ASSERT_EQ(0, obj.RunAccumulated());
ASSERT_EQ(3, obj.GetSelectedOutputStringLineCount()); ASSERT_EQ(3, obj.GetSelectedOutputStringLineCount());
} }
TEST(TestIPhreeqc, TestGetSelectedOutputStringLineCountMultipleRuns)
{
IPhreeqc obj;
int retval = 0;
ASSERT_EQ(0, obj.LoadDatabase("llnl.dat"));
ASSERT_EQ(false, obj.GetSelectedOutputStringOn());
obj.SetSelectedOutputStringOn(true);
ASSERT_EQ(true, obj.GetSelectedOutputStringOn());
retval = obj.RunString(R"(
SOLUTION 1
C 1
Ca 1
Na 1
EQUILIBRIUM_PHASES
calcite 0 0.01
SELECTED_OUTPUT
-totals C Ca Na
)");
ASSERT_EQ(0, retval);
ASSERT_EQ(3, obj.GetSelectedOutputStringLineCount()); // header + i_soln + react
retval = obj.RunString(R"(
SOLUTION 1
C 2
Ca 2
Na 2
)");
ASSERT_EQ(0, retval);
ASSERT_EQ(2, obj.GetSelectedOutputStringLineCount()); // header + i_soln
}
TEST(TestIPhreeqc, TestSelectedOutputFileMultipleRuns)
{
FileTest selout("TestSelectedOutputFileMultipleRuns.sel");
ASSERT_TRUE(selout.RemoveExisting());
IPhreeqc obj;
int retval = 0;
ASSERT_EQ(0, obj.LoadDatabase("llnl.dat"));
ASSERT_EQ(false, obj.GetSelectedOutputFileOn());
obj.SetSelectedOutputFileOn(true);
ASSERT_EQ(true, obj.GetSelectedOutputFileOn());
retval = obj.RunString(R"(
SOLUTION 1
C 1
Ca 1
Na 1
EQUILIBRIUM_PHASES
calcite 0 0.01
SELECTED_OUTPUT
-file TestSelectedOutputFileMultipleRuns.sel
-totals C Ca Na
)");
ASSERT_EQ(0, retval);
ASSERT_EQ(3, selout.LineCount()); // header + i_soln + react
retval = obj.RunString(R"(
SOLUTION 1
C 2
Ca 2
Na 2
)");
ASSERT_EQ(0, retval);
ASSERT_EQ(2, selout.LineCount()); // header + i_soln
}
TEST(TestIPhreeqc, TestGetSelectedOutputRowCountMultipleRuns)
{
IPhreeqc obj;
ASSERT_EQ(0, obj.LoadDatabase("llnl.dat"));
obj.RunString(R"(
SOLUTION 1
C 1
Ca 1
Na 1
EQUILIBRIUM_PHASES
calcite 0 0.01
SELECTED_OUTPUT
-totals C Ca Na
)");
ASSERT_EQ(3, obj.GetSelectedOutputRowCount()); // header + i_soln + react
obj.RunString(R"(
SOLUTION 1
C 2
Ca 2
Na 2
)");
ASSERT_EQ(2, obj.GetSelectedOutputRowCount()); // header + i_soln
}
TEST(TestIPhreeqc, TestGetSelectedOutputStringLine) TEST(TestIPhreeqc, TestGetSelectedOutputStringLine)
{ {
IPhreeqc obj; IPhreeqc obj;
@ -3299,8 +3409,9 @@ TEST(TestIPhreeqc, TestGetSelectedOutputStringLine)
ASSERT_EQ(VR_OK, ::EQUILIBRIUM_PHASES(obj, "calcite", 0.0, 0.010)); ASSERT_EQ(VR_OK, ::EQUILIBRIUM_PHASES(obj, "calcite", 0.0, 0.010));
ASSERT_EQ(VR_OK, ::USER_PUNCH(obj, "Ca", max)); ASSERT_EQ(VR_OK, ::USER_PUNCH(obj, "Ca", max));
ASSERT_EQ(false, obj.GetSelectedOutputStringOn() != 0); ASSERT_EQ(false, obj.GetSelectedOutputStringOn());
obj.SetSelectedOutputStringOn(true); obj.SetSelectedOutputStringOn(true);
ASSERT_EQ(true, obj.GetSelectedOutputStringOn());
ASSERT_EQ(0, obj.RunAccumulated()); ASSERT_EQ(0, obj.RunAccumulated());
ASSERT_EQ(3, obj.GetSelectedOutputStringLineCount()); ASSERT_EQ(3, obj.GetSelectedOutputStringLineCount());

View File

@ -1103,17 +1103,8 @@ void IPhreeqc::UnLoadDatabase(void)
delete (*itt).second; delete (*itt).second;
} }
this->SelectedOutputMap.clear(); this->SelectedOutputMap.clear();
this->SelectedOutputStringMap.clear();
std::map< int, std::string >::iterator mit = this->SelectedOutputStringMap.begin(); this->SelectedOutputLinesMap.clear();
for (; mit != this->SelectedOutputStringMap.begin(); ++mit)
{
(*mit).second.clear();
}
std::map< int, std::vector< std::string > >::iterator it = this->SelectedOutputLinesMap.begin();
for (; it != this->SelectedOutputLinesMap.begin(); ++it)
{
(*it).second.clear();
}
// clear dump string // clear dump string
@ -1165,6 +1156,7 @@ void IPhreeqc::check_database(const char* sz_routine)
} }
this->SelectedOutputMap.clear(); this->SelectedOutputMap.clear();
this->SelectedOutputStringMap.clear(); this->SelectedOutputStringMap.clear();
this->SelectedOutputLinesMap.clear();
// release // release
this->LogString.clear(); this->LogString.clear();
@ -1172,16 +1164,6 @@ void IPhreeqc::check_database(const char* sz_routine)
this->OutputString.clear(); this->OutputString.clear();
this->OutputLines.clear(); this->OutputLines.clear();
std::map< int, std::string >::iterator mit = SelectedOutputStringMap.begin();
for (; mit != SelectedOutputStringMap.begin(); ++mit)
{
(*mit).second.clear();
}
std::map< int, std::vector< std::string > >::iterator lit = this->SelectedOutputLinesMap.begin();
for (; lit != this->SelectedOutputLinesMap.begin(); ++lit)
{
(*lit).second.clear();
}
if (!this->DatabaseLoaded) if (!this->DatabaseLoaded)
{ {
@ -1245,6 +1227,18 @@ void IPhreeqc::do_run(const char* sz_routine, std::istream* pis, PFN_PRERUN_CALL
this->PhreeqcPtr->dup_print(token, TRUE); this->PhreeqcPtr->dup_print(token, TRUE);
if (this->PhreeqcPtr->read_input() == EOF) if (this->PhreeqcPtr->read_input() == EOF)
break; break;
if (this->PhreeqcPtr->simulation == 1)
{
// force headings for selected output (on every call to do_run)
// might want to split tidy_punch to avoid duplicate searches like master_bsearch
std::map< int, SelectedOutput >::iterator pit = this->PhreeqcPtr->SelectedOutput_map.begin();
for (; pit != this->PhreeqcPtr->SelectedOutput_map.end(); ++pit)
{
(*pit).second.Set_new_def(true);
this->PhreeqcPtr->keycount[Keywords::KEY_SELECTED_OUTPUT] = 1;
}
}
// bool bWarning = false; // bool bWarning = false;
std::map< int, SelectedOutput >::iterator mit = this->PhreeqcPtr->SelectedOutput_map.begin(); std::map< int, SelectedOutput >::iterator mit = this->PhreeqcPtr->SelectedOutput_map.begin();