Skip to content

Commit

Permalink
added StreamFactory system
Browse files Browse the repository at this point in the history
  • Loading branch information
mpgerlek committed Mar 27, 2012
1 parent 7a4ea56 commit f030eb7
Show file tree
Hide file tree
Showing 3 changed files with 386 additions and 1 deletion.
92 changes: 92 additions & 0 deletions include/pdal/StreamManager.hpp
Expand Up @@ -37,16 +37,108 @@

#include <pdal/pdal_internal.hpp>

#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file.hpp>
#ifdef PDAL_COMPILER_MSVC
# pragma warning(push)
# pragma warning(disable: 4512) // assignment operator could not be generated
#endif
#include <boost/iostreams/restrict.hpp>
#ifdef PDAL_COMPILER_MSVC
# pragma warning(pop)
#endif

#include <string>
#include <cassert>
#include <stdexcept>
#include <cmath>
#include <ostream>
#include <istream>
#include <vector>

namespace pdal
{


class PDAL_DLL StreamFactory
{
public:
StreamFactory() {}
virtual ~StreamFactory() {}

// returns the stream in the open state
virtual std::istream& allocate() = 0;

// will close the stream for you
virtual void deallocate(std::istream&) = 0;

private:
StreamFactory(const StreamFactory&); // nope
StreamFactory& operator=(const StreamFactory&); // nope
};


// this one can't clone its stream!
class PDAL_DLL PassthruStreamFactory : public StreamFactory
{
public:
PassthruStreamFactory(std::istream& s);
virtual ~PassthruStreamFactory();

virtual std::istream& allocate();
virtual void deallocate(std::istream&);

private:
std::istream& m_istream;
bool m_allocated;
};


class PDAL_DLL FilenameStreamFactory : public StreamFactory
{
public:
FilenameStreamFactory(const std::string& file);
virtual ~FilenameStreamFactory();

virtual std::istream& allocate();
virtual void deallocate(std::istream&);

private:
const std::string m_filename;
std::vector<std::istream*> m_istreams;
};

class PDAL_DLL FilenameSubsetStreamFactory : public StreamFactory
{
public:
FilenameSubsetStreamFactory(const std::string& file, boost::uint64_t offset, boost::uint64_t length);
virtual ~FilenameSubsetStreamFactory();

virtual std::istream& allocate();
virtual void deallocate(std::istream&);

private:
const std::string m_filename;
const boost::uint64_t m_offset;
const boost::uint64_t m_length;

typedef boost::iostreams::stream<boost::iostreams::file_source> FStream;
typedef boost::iostreams::restriction<FStream> FStreamSlice;
typedef boost::iostreams::stream<FStreamSlice> FStreamSliceStream;

struct StreamSet
{
StreamSet(std::istream*,FStreamSlice*,FStreamSliceStream*);
~StreamSet();
bool match(std::istream&) const;
std::istream* stream;
FStreamSlice* slice;
FStreamSliceStream* streamslice;
};
std::vector<StreamSet*> m_streams;
};


// Many of our reader & writer classes want to take a filename or a stream
// in their ctors, which means that we need a common piece of code that
// creates and takes ownership of the stream, if needed.
Expand Down
184 changes: 183 additions & 1 deletion src/StreamManager.cpp
Expand Up @@ -35,10 +35,192 @@
#include <pdal/StreamManager.hpp>
#include <pdal/FileUtils.hpp>


namespace pdal
{

// --------------------------------------------------------------------

PassthruStreamFactory::PassthruStreamFactory(std::istream& s)
: StreamFactory()
, m_istream(s)
, m_allocated(false)
{
return;
}

PassthruStreamFactory::~PassthruStreamFactory()
{
return;
}

std::istream& PassthruStreamFactory::allocate()
{
if (m_allocated)
throw pdal_error("can't allocate additional stream");

m_allocated = true;
return m_istream;
}


void PassthruStreamFactory::deallocate(std::istream& stream)
{
if (!m_allocated)
throw pdal_error("incorrect stream deallocation");

if (&stream != &m_istream)
throw pdal_error("incorrect stream deallocation");

m_allocated = false;
}


// --------------------------------------------------------------------

FilenameStreamFactory::FilenameStreamFactory(const std::string& name)
: StreamFactory()
, m_filename(name)
{
return;
}

FilenameStreamFactory::~FilenameStreamFactory()
{
while (m_istreams.size())
{
std::istream* s = m_istreams.back();
m_istreams.pop_back();
if (s)
{
FileUtils::closeFile(s);
}
}

return;
}


std::istream& FilenameStreamFactory::allocate()
{
std::istream* s = FileUtils::openFile(m_filename, true);
m_istreams.push_back(s);
return *s;
}


void FilenameStreamFactory::deallocate(std::istream& stream)
{
for (unsigned int i=0; i<m_istreams.size(); i++)
{
if (m_istreams[i] == &stream)
{
FileUtils::closeFile(m_istreams[i]);
m_istreams[i] = NULL;
return;
}
}

throw pdal_error("incorrect stream deallocation");
}


// --------------------------------------------------------------------

FilenameSubsetStreamFactory::StreamSet::StreamSet(std::istream* a, FStreamSlice* b, FStreamSliceStream* c)
: stream(a)
, slice(b)
, streamslice(c)
{
return;
}


FilenameSubsetStreamFactory::StreamSet::~StreamSet()
{
streamslice->close();
delete streamslice;

slice->close();
delete slice;

FileUtils::closeFile(stream);

return;
}


bool FilenameSubsetStreamFactory::StreamSet::match(std::istream& s) const
{
std::istream* ss(&s);
return ss == streamslice;
}


FilenameSubsetStreamFactory::FilenameSubsetStreamFactory(const std::string& name, boost::uint64_t offset, boost::uint64_t length)
: StreamFactory()
, m_filename(name)
, m_offset(offset)
, m_length(length)
{
return;
}

FilenameSubsetStreamFactory::~FilenameSubsetStreamFactory()
{
namespace io = boost::iostreams;

for (unsigned int i=0; i<m_streams.size(); i++)
{
StreamSet* set = m_streams[i];
if (set)
{
delete set;
m_streams[i] = NULL;
}
}

return;
}


std::istream& FilenameSubsetStreamFactory::allocate()
{
namespace io = boost::iostreams;

std::istream* file = FileUtils::openFile(m_filename, true);

FStream* source = dynamic_cast<FStream*>(file);
assert(source!=0);

FStreamSlice* restricted_device = new FStreamSlice(*source, m_offset, m_length);
io::stream<FStreamSlice>* restricted_stream = new io::stream<FStreamSlice>(*restricted_device);

StreamSet* set = new StreamSet(file, restricted_device, restricted_stream);
m_streams.push_back(set);

return *restricted_stream;
}


void FilenameSubsetStreamFactory::deallocate(std::istream& stream)
{
for (unsigned int i=0; i<m_streams.size(); i++)
{
StreamSet* set = m_streams[i];
if (set && set->match(stream))
{
delete set;
m_streams[i] = NULL;
return;
}
}

throw pdal_error("incorrect stream deallocation");
}


// --------------------------------------------------------------------


StreamManagerBase::StreamManagerBase(const std::string& filename, Type type)
: m_isOpen(false)
Expand Down

0 comments on commit f030eb7

Please sign in to comment.