summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-09-10 16:21:55 +0000
committerTavian Barnes <tavianator@gmail.com>2009-09-10 16:21:55 +0000
commit080d202c75f0c0887d11daf5186ee51c1e82b6c3 (patch)
tree73df35153e5abc7776657d2681e2a010f03b7c5f
parentc6664a06093a9da96028d4f5488dbcab6ecab5b4 (diff)
downloaddimension-080d202c75f0c0887d11daf5186ee51c1e82b6c3.tar.xz
New iostream-style diamond inheritance pattern for FILE_Cookie:
iFILE_Cookie, oFILE_Cookie, ioFILE_Cookie.
-rw-r--r--libdimensionxx/cookie-fopencookie.cpp123
-rw-r--r--libdimensionxx/cookie-tmpfile.cpp102
-rw-r--r--libdimensionxx/dimensionxx/cookie.hpp70
-rw-r--r--libdimensionxx/png.cpp8
4 files changed, 128 insertions, 175 deletions
diff --git a/libdimensionxx/cookie-fopencookie.cpp b/libdimensionxx/cookie-fopencookie.cpp
index f44ae7b..b44b5dd 100644
--- a/libdimensionxx/cookie-fopencookie.cpp
+++ b/libdimensionxx/cookie-fopencookie.cpp
@@ -34,20 +34,24 @@
namespace Dimension
{
+ // FILE_Cookie pure virtual destructor: close the file
+ FILE_Cookie::~FILE_Cookie() { std::fclose(m_file); }
+
namespace
{
// Cookie read function
ssize_t
cookie_read(void* cookie, char* buf, size_t size)
{
- FILE_Cookie* streams = reinterpret_cast<FILE_Cookie*>(cookie);
+ FILE_Cookie* fcookie = reinterpret_cast<FILE_Cookie*>(cookie);
+ iFILE_Cookie& ifcookie = dynamic_cast<iFILE_Cookie&>(*fcookie);
// Do the unformatted read
- streams->istr().read(buf, size);
+ ifcookie.istr().read(buf, size);
- if (streams->istr().eof() || streams->istr().good()) {
- return streams->istr().gcount(); // This returns 0 on an immediate EOF
- // for us.
+ if (ifcookie.istr().eof() || ifcookie.istr().good()) {
+ return ifcookie.istr().gcount(); // This returns 0 on an immediate EOF
+ // for us.
} else {
// Some non-EOF error
return -1;
@@ -58,12 +62,13 @@ namespace Dimension
ssize_t
cookie_write(void* cookie, const char* buf, size_t size)
{
- FILE_Cookie* streams = reinterpret_cast<FILE_Cookie*>(cookie);
+ FILE_Cookie* fcookie = reinterpret_cast<FILE_Cookie*>(cookie);
+ oFILE_Cookie& ofcookie = dynamic_cast<oFILE_Cookie&>(*fcookie);
// Do the unformatted write
- streams->ostr().write(buf, size);
+ ofcookie.ostr().write(buf, size);
- if (streams->ostr().good()) {
+ if (ofcookie.ostr().good()) {
// Write operation succeeded, so we must've written size bytes
return size;
} else {
@@ -76,42 +81,44 @@ namespace Dimension
int
cookie_seek(void* cookie, off64_t* offset, int whence)
{
- FILE_Cookie* streams = reinterpret_cast<FILE_Cookie*>(cookie);
+ FILE_Cookie* fcookie = reinterpret_cast<FILE_Cookie*>(cookie);
+ iFILE_Cookie* ifcookie = dynamic_cast<iFILE_Cookie*>(fcookie);
+ oFILE_Cookie* ofcookie = dynamic_cast<oFILE_Cookie*>(fcookie);
- if (streams->is_input()) {
+ if (ifcookie) {
// If we have an input stream, seek it
switch (whence) {
case SEEK_SET:
- streams->istr().seekg(*offset, std::ios::beg);
+ ifcookie->istr().seekg(*offset, std::ios::beg);
break;
case SEEK_CUR:
- streams->istr().seekg(*offset, std::ios::cur);
+ ifcookie->istr().seekg(*offset, std::ios::cur);
break;
case SEEK_END:
- streams->istr().seekg(*offset, std::ios::end);
+ ifcookie->istr().seekg(*offset, std::ios::end);
break;
}
- if (!streams->istr().good()) {
+ if (!ifcookie->istr().good()) {
// Seek failed
return 1;
}
}
- if (streams->is_output()) {
+ if (ofcookie) {
// If we have an output stream, seek it
switch (whence) {
case SEEK_SET:
- streams->ostr().seekp(*offset, std::ios::beg);
+ ofcookie->ostr().seekp(*offset, std::ios::beg);
break;
case SEEK_CUR:
- streams->ostr().seekp(*offset, std::ios::cur);
+ ofcookie->ostr().seekp(*offset, std::ios::cur);
break;
case SEEK_END:
- streams->ostr().seekp(*offset, std::ios::end);
+ ofcookie->ostr().seekp(*offset, std::ios::end);
}
- if (!streams->ostr().good()) {
+ if (!ofcookie->ostr().good()) {
// Seek failed
return 1;
}
@@ -123,8 +130,8 @@ namespace Dimension
}
// Make an input FILE_Cookie
- FILE_Cookie::FILE_Cookie(std::istream& istr)
- : m_istr(&istr), m_ostr(0)
+ iFILE_Cookie::iFILE_Cookie(std::istream& istr)
+ : m_istr(&istr)
{
cookie_io_functions_t io_funcs;
io_funcs.read = &cookie_read;
@@ -132,12 +139,13 @@ namespace Dimension
io_funcs.seek = &cookie_seek;
io_funcs.close = 0;
- m_file = fopencookie(reinterpret_cast<void*>(this), "r", io_funcs);
+ // Set the FILE*
+ file(fopencookie(reinterpret_cast<void*>(this), "r", io_funcs));
}
// Make an output FILE_Cookie
- FILE_Cookie::FILE_Cookie(std::ostream& ostr)
- : m_istr(0), m_ostr(&ostr)
+ oFILE_Cookie::oFILE_Cookie(std::ostream& ostr)
+ : m_ostr(&ostr)
{
cookie_io_functions_t io_funcs;
io_funcs.read = 0;
@@ -145,12 +153,16 @@ namespace Dimension
io_funcs.seek = &cookie_seek;
io_funcs.close = 0;
- m_file = fopencookie(reinterpret_cast<void*>(this), "w", io_funcs);
+ // Set the FILE*
+ file(fopencookie(reinterpret_cast<void*>(this), "w", io_funcs));
}
+ // No-op oFILE_Cookie destructor
+ oFILE_Cookie::~oFILE_Cookie() { }
+
// Make an I/O FILE_Cookie
- FILE_Cookie::FILE_Cookie(std::iostream& iostr)
- : m_istr(&iostr), m_ostr(&iostr)
+ ioFILE_Cookie::ioFILE_Cookie(std::iostream& iostr)
+ : iFILE_Cookie(iostr, 0), oFILE_Cookie(iostr, 0)
{
cookie_io_functions_t io_funcs;
io_funcs.read = &cookie_read;
@@ -158,61 +170,6 @@ namespace Dimension
io_funcs.seek = &cookie_seek;
io_funcs.close = 0;
- m_file = fopencookie(reinterpret_cast<void*>(this), "r+", io_funcs);
- }
-
- // Close the file
- FILE_Cookie::~FILE_Cookie() { std::fclose(m_file); }
-
- // Get the FILE*
- FILE* FILE_Cookie::file() { return m_file; }
- const FILE* FILE_Cookie::file() const { return m_file; }
-
- bool FILE_Cookie::is_input() const { return m_istr; }
- bool FILE_Cookie::is_output() const { return m_ostr; }
-
- // Get the C++ streams
-
- std::istream&
- FILE_Cookie::istr()
- {
- if (is_input()) {
- return *m_istr;
- } else {
- throw Dimension_Error("Attempted to get input stream from non-input"
- " FILE_Cookie.");
- }
- }
-
- const std::istream&
- FILE_Cookie::istr() const
- {
- if (is_input()) {
- return *m_istr;
- } else {
- throw Dimension_Error("Attempted to get input stream from non-input"
- " FILE_Cookie.");
- }
- }
-
- std::ostream&
- FILE_Cookie::ostr()
- {
- if (is_output()) {
- return *m_ostr;
- } else {
- throw Dimension_Error("Attempted to get output stream from non-input"
- " FILE_Cookie.");
- }
- }
-
- const std::ostream& FILE_Cookie::ostr() const
- {
- if (is_output()) {
- return *m_ostr;
- } else {
- throw Dimension_Error("Attempted to get output stream from non-input"
- " FILE_Cookie.");
- }
+ file(fopencookie(reinterpret_cast<void*>(this), "r+", io_funcs));
}
}
diff --git a/libdimensionxx/cookie-tmpfile.cpp b/libdimensionxx/cookie-tmpfile.cpp
index 7efefce..9e513e6 100644
--- a/libdimensionxx/cookie-tmpfile.cpp
+++ b/libdimensionxx/cookie-tmpfile.cpp
@@ -25,6 +25,9 @@
namespace Dimension
{
+ // Close the tmpfile
+ FILE_Cookie::~FILE_Cookie() { std::fclose(m_file); }
+
namespace
{
// Write an input stream completely to a FILE*; this works poorly for
@@ -91,99 +94,56 @@ namespace Dimension
}
// Make an input FILE_Cookie
- FILE_Cookie::FILE_Cookie(std::istream& istr)
- : m_file(std::tmpfile()), m_istr(&istr), m_ostr(0)
+ iFILE_Cookie::iFILE_Cookie(std::istream& istr)
+ : m_istr(&istr)
{
- if (!m_file) {
+ FILE* tmp = std::tmpfile();
+ if (!tmp) {
throw Dimension_Error("Error opening temporary file for C++/C I/O"
" interface.");
}
// Write the input stream to the temporary file
- write_cookie(m_file, *m_istr);
- }
+ write_cookie(tmp, *m_istr);
- // Make an output FILE_Cookie
- FILE_Cookie::FILE_Cookie(std::ostream& ostr)
- : m_file(std::tmpfile()), m_istr(0), m_ostr(&ostr)
- {
- if (!m_file) {
- throw Dimension_Error("Error opening temporary file for C++/C I/O"
- " interface.");
- }
+ // Set the FILE*
+ file(tmp);
}
- // Make an I/O FILE_Cookie
- FILE_Cookie::FILE_Cookie(std::iostream& iostr)
- : m_file(std::tmpfile()), m_istr(&iostr), m_ostr(&iostr)
+ // Make an output FILE_Cookie
+ oFILE_Cookie::oFILE_Cookie(std::ostream& ostr)
+ : m_ostr(&ostr)
{
- if (!m_file) {
+ FILE* tmp = std::tmpfile();
+ if (!tmp) {
throw Dimension_Error("Error opening temporary file for C++/C I/O"
" interface.");
}
- // Write the input stream to the temporary file
- write_cookie(m_file, *m_istr);
- }
-
- // Close the tmpfile, maybe syncing a C++ stream to it first
- FILE_Cookie::~FILE_Cookie() {
- if (is_output()) {
- read_cookie(*m_ostr, m_file);
- }
-
- std::fclose(m_file);
+ // Set the FILE*
+ file(tmp);
}
- // Get the FILE*
- FILE* FILE_Cookie::file() { return m_file; }
- const FILE* FILE_Cookie::file() const { return m_file; }
-
- bool FILE_Cookie::is_input() const { return m_istr; }
- bool FILE_Cookie::is_output() const { return m_ostr; }
-
- // Get the C++ streams
-
- std::istream&
- FILE_Cookie::istr()
+ // Write the temporary file to the output stream
+ oFILE_Cookie::~oFILE_Cookie()
{
- if (is_input()) {
- return *m_istr;
- } else {
- throw Dimension_Error("Attempted to get input stream from non-input"
- " FILE_Cookie.");
- }
+ read_cookie(ostr(), file());
}
- const std::istream&
- FILE_Cookie::istr() const
+ // Make an I/O FILE_Cookie
+ ioFILE_Cookie::ioFILE_Cookie(std::iostream& iostr)
+ : iFILE_Cookie(iostr, 0), oFILE_Cookie(iostr, 0)
{
- if (is_input()) {
- return *m_istr;
- } else {
- throw Dimension_Error("Attempted to get input stream from non-input"
- " FILE_Cookie.");
+ FILE* tmp = std::tmpfile();
+ if (!tmp) {
+ throw Dimension_Error("Error opening temporary file for C++/C I/O"
+ " interface.");
}
- }
- std::ostream&
- FILE_Cookie::ostr()
- {
- if (is_output()) {
- return *m_ostr;
- } else {
- throw Dimension_Error("Attempted to get output stream from non-input"
- " FILE_Cookie.");
- }
- }
+ // Write the input stream to the temporary file
+ write_cookie(tmp, istr());
- const std::ostream& FILE_Cookie::ostr() const
- {
- if (is_output()) {
- return *m_ostr;
- } else {
- throw Dimension_Error("Attempted to get output stream from non-input"
- " FILE_Cookie.");
- }
+ // Set the FILE*
+ file(tmp);
}
}
diff --git a/libdimensionxx/dimensionxx/cookie.hpp b/libdimensionxx/dimensionxx/cookie.hpp
index 0b8beb9..d5b042e 100644
--- a/libdimensionxx/dimensionxx/cookie.hpp
+++ b/libdimensionxx/dimensionxx/cookie.hpp
@@ -29,38 +29,74 @@
namespace Dimension
{
- // Simple RAII class for FILE*'s which interface with a C++ stream.
+ // Simple RAII classes for FILE*'s which interface with a C++ stream.
+
class FILE_Cookie
{
public:
- FILE_Cookie(std::istream& istr);
- FILE_Cookie(std::ostream& ostr);
- FILE_Cookie(std::iostream& iostr);
- ~FILE_Cookie();
+ // Destructor made pure virtual
+ virtual ~FILE_Cookie() = 0;
// Get the magic FILE*
- FILE* file();
- const FILE* file() const;
+ FILE* file() { return m_file; }
+ const FILE* file() const { return m_file; }
- // Are we an input or output stream?
- bool is_input() const;
- bool is_output() const;
+ protected:
+ FILE_Cookie() { }
- // Get the C++ streams
- std::istream& istr();
- const std::istream& istr() const;
- std::ostream& ostr();
- const std::ostream& ostr() const;
+ // Set the underlying FILE*
+ void file(FILE* file) { m_file = file; }
private:
std::FILE* m_file;
- std::istream* m_istr;
- std::ostream* m_ostr;
// Copying prohibited
FILE_Cookie(const FILE_Cookie& cookie);
FILE_Cookie& operator=(const FILE_Cookie& cookie);
};
+
+ class iFILE_Cookie : public virtual FILE_Cookie
+ {
+ public:
+ iFILE_Cookie(std::istream& istr);
+ // virtual ~iFILE_Cookie();
+
+ // Get the C++ streams
+ std::istream& istr() { return *m_istr; }
+ const std::istream& istr() const { return *m_istr; }
+
+ protected:
+ // Just set the istream without initializing the FILE*
+ iFILE_Cookie(std::istream& istr, int) : m_istr(&istr) { }
+
+ private:
+ std::istream* m_istr;
+ };
+
+ class oFILE_Cookie : public virtual FILE_Cookie
+ {
+ public:
+ oFILE_Cookie(std::ostream& ostr);
+ virtual ~oFILE_Cookie();
+
+ // Get the C++ streams
+ std::ostream& ostr() { return *m_ostr; }
+ const std::ostream& ostr() const { return *m_ostr; }
+
+ protected:
+ // Just set the istream without initializing the FILE*
+ oFILE_Cookie(std::ostream& ostr, int) : m_ostr(&ostr) { }
+
+ private:
+ std::ostream* m_ostr;
+ };
+
+ class ioFILE_Cookie : public iFILE_Cookie, public oFILE_Cookie
+ {
+ public:
+ ioFILE_Cookie(std::iostream& iostr);
+ // virtual ~ioFILE_Cookie();
+ };
}
#endif /* DIMENSIONXX_COOKIE_HPP */
diff --git a/libdimensionxx/png.cpp b/libdimensionxx/png.cpp
index 8853c5b..92bfc15 100644
--- a/libdimensionxx/png.cpp
+++ b/libdimensionxx/png.cpp
@@ -55,7 +55,7 @@ namespace Dimension
}
// Make the C++/C I/O interface
- FILE_Cookie cookie(*m_ostr);
+ oFILE_Cookie cookie(*m_ostr);
// Write the PNG file
if (dmnsn_png_write_canvas(m_canvas->dmnsn(), cookie.file()) != 0) {
@@ -81,7 +81,7 @@ namespace Dimension
Persister persister;
// Make the C++/C I/O interface
- FILE_Cookie* cookie = new FILE_Cookie(*m_ostr);
+ FILE_Cookie* cookie = new oFILE_Cookie(*m_ostr);
persister.persist(cookie);
// Start the asynchronous task
@@ -110,7 +110,7 @@ namespace Dimension
}
// Make the C++/C I/O interface
- FILE_Cookie cookie(*m_istr);
+ iFILE_Cookie cookie(*m_istr);
// Read the canvas from a PNG file
dmnsn_canvas* canvas = dmnsn_png_read_canvas(cookie.file());
@@ -146,7 +146,7 @@ namespace Dimension
persister.persist(canvas);
// Make the C++/C I/O interface
- FILE_Cookie* cookie = new FILE_Cookie(*m_istr);
+ iFILE_Cookie* cookie = new iFILE_Cookie(*m_istr);
persister.persist(cookie);
// Start the asynchronous task