flatten 20260225
This commit is contained in:
85
tjp/core/pipe/Pipe.h
Executable file
85
tjp/core/pipe/Pipe.h
Executable file
@@ -0,0 +1,85 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <tjp/core/types/Types.h>
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
#include <string.h>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
template<typename Packet, typename Mutex=core::Mutex>
|
||||
struct Pipe
|
||||
{
|
||||
mutable Mutex mutex;
|
||||
|
||||
Pipe();
|
||||
~Pipe();
|
||||
|
||||
typedef std::list<Packet> PacketList;
|
||||
PacketList pipe;
|
||||
size_t size_;
|
||||
bool open;
|
||||
bool flush_;
|
||||
|
||||
size_t sizeReadRequested = 0;
|
||||
size_t sizeRead = 0;
|
||||
void clearSizeRead();
|
||||
|
||||
size_t write (Packet &&);
|
||||
size_t write_no_lock (Packet &&);
|
||||
|
||||
Packet read ();
|
||||
Packet read_no_lock ();
|
||||
|
||||
bool empty() const;
|
||||
bool empty_no_lock() const;
|
||||
|
||||
void close();
|
||||
bool isOpen() const;
|
||||
bool eos() const;
|
||||
bool finishing() const;
|
||||
bool flushing() const;
|
||||
|
||||
void flush() { flush_ = true; }
|
||||
bool flushed();
|
||||
|
||||
size_t offset;
|
||||
|
||||
template<typename PipeOut>
|
||||
void readInto (PipeOut &rhs)
|
||||
{
|
||||
while (!empty())
|
||||
{
|
||||
rhs.write(read());
|
||||
}
|
||||
|
||||
if (flushed())
|
||||
rhs.flush();
|
||||
}
|
||||
|
||||
size_t read (char *buffer, size_t size_t);
|
||||
size_t read_no_lock (char *buffer, size_t size_t);
|
||||
|
||||
size_t write (const char *buffer, size_t size_t);
|
||||
size_t peek (char *buffer, size_t size_t) const;
|
||||
size_t peek_no_lock (char *buffer, size_t size_t) const;
|
||||
|
||||
size_t skip(size_t size);
|
||||
size_t skip_no_lock(size_t size);
|
||||
|
||||
size_t resize (size_t maximumSize);
|
||||
|
||||
size_t size () const;
|
||||
const Packet *peek() const;
|
||||
|
||||
void clear();
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#include "Pipe.inl"
|
||||
|
||||
294
tjp/core/pipe/Pipe.inl
Executable file
294
tjp/core/pipe/Pipe.inl
Executable file
@@ -0,0 +1,294 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include "Pipe.h"
|
||||
#include <tjp/core/assert/debug_assert.h>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
Pipe<Packet,Mutex>::Pipe () :
|
||||
offset(0),
|
||||
size_(0),
|
||||
open(true)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
Pipe<Packet,Mutex>::~Pipe ()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
void Pipe<Packet,Mutex>::close()
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
open = false;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
bool Pipe<Packet,Mutex>::isOpen() const
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
return open;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::write_no_lock (Packet &&packet)
|
||||
{
|
||||
debug_assert(mutex.locked_by_caller());
|
||||
|
||||
if (packet.size() == 0)
|
||||
return size_;
|
||||
|
||||
size_ += packet.size();
|
||||
pipe.emplace_back(std::move(packet));
|
||||
|
||||
return size_;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::write (Packet &&packet)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
return write_no_lock(std::move(packet));
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
Packet Pipe<Packet,Mutex>::read_no_lock ()
|
||||
{
|
||||
debug_assert(!pipe.empty());
|
||||
debug_assert(offset == 0);
|
||||
debug_assert(mutex.locked_by_caller());
|
||||
|
||||
auto p = std::move(pipe.front());
|
||||
pipe.pop_front();
|
||||
|
||||
debug_assert(size_ >= p.size());
|
||||
size_ -= p.size();
|
||||
offset = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
Packet Pipe<Packet,Mutex>::read ()
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
return read_no_lock();
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
bool Pipe<Packet,Mutex>::empty_no_lock() const
|
||||
{
|
||||
return pipe.empty();
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
bool Pipe<Packet,Mutex>::empty() const
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
return empty_no_lock();
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::peek_no_lock (char *buffer, size_t size) const
|
||||
{
|
||||
debug_assert(mutex.locked_by_caller());
|
||||
|
||||
size_t ptr = 0;
|
||||
size_t offset = this->offset;
|
||||
|
||||
auto &buffers = pipe;
|
||||
|
||||
typename PacketList::const_iterator i=buffers.begin();
|
||||
while (i!=buffers.end() && (size > 0))
|
||||
{
|
||||
auto chunksize = i->size() - offset;
|
||||
size_t newoffset = 0;
|
||||
|
||||
if (chunksize > size)
|
||||
{
|
||||
newoffset = offset + size;
|
||||
chunksize = size;
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
memcpy (buffer + ptr, i->data() + offset, chunksize);
|
||||
|
||||
ptr += chunksize;
|
||||
size -= chunksize;
|
||||
offset = newoffset;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::peek (char *buffer, size_t size) const
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
return peek_no_lock(buffer, size);
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::read_no_lock (char *buffer, size_t requestedSize)
|
||||
{
|
||||
auto size = requestedSize;
|
||||
size_t ptr = 0;
|
||||
|
||||
auto &buffers = pipe;
|
||||
|
||||
while (!buffers.empty() && (size > 0))
|
||||
{
|
||||
auto chunksize = buffers.front().size() - offset;
|
||||
size_t newoffset = 0;
|
||||
|
||||
if (chunksize > size)
|
||||
{
|
||||
newoffset = offset + size;
|
||||
chunksize = size;
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
debug_assert(ptr + chunksize <= requestedSize);
|
||||
memcpy (buffer + ptr, buffers.front().data() + offset, chunksize);
|
||||
}
|
||||
|
||||
ptr += chunksize;
|
||||
size -= chunksize;
|
||||
offset = newoffset;
|
||||
|
||||
if (offset == 0)
|
||||
{
|
||||
size_ -= buffers.front().size();
|
||||
buffers.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
sizeReadRequested += requestedSize;
|
||||
sizeRead += ptr;
|
||||
|
||||
return ptr;
|
||||
} ;
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
void Pipe<Packet,Mutex>::clearSizeRead ()
|
||||
{
|
||||
sizeReadRequested = sizeRead = 0;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::read (char *buffer, size_t requestedSize)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
return read_no_lock(buffer, requestedSize);
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::write (const char *buffer, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return size;
|
||||
|
||||
write(Packet(buffer, buffer+size));
|
||||
return size;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::skip_no_lock(size_t size)
|
||||
{
|
||||
return read_no_lock(nullptr, size);
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::skip(size_t size)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
return skip_no_lock(size);
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::size () const
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
return size_ - offset;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
void Pipe<Packet,Mutex>::clear ()
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
pipe.clear();
|
||||
size_ = offset = 0;
|
||||
flush_ = false;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
size_t Pipe<Packet,Mutex>::resize (size_t maximumSize)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
if (size_ > maximumSize)
|
||||
{
|
||||
skip_no_lock(size_ - maximumSize);
|
||||
}
|
||||
|
||||
return size_;
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
const Packet *Pipe<Packet,Mutex>::peek() const
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
if (pipe.empty())
|
||||
return nullptr;
|
||||
|
||||
return &pipe.front();
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
bool Pipe<Packet,Mutex>::eos() const
|
||||
{
|
||||
return !open && empty();
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
bool Pipe<Packet,Mutex>::finishing() const
|
||||
{
|
||||
return !open && !empty();
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
bool Pipe<Packet,Mutex>::flushing() const
|
||||
{
|
||||
return flush_ && !empty();
|
||||
}
|
||||
|
||||
template<typename Packet, typename Mutex>
|
||||
bool Pipe<Packet,Mutex>::flushed()
|
||||
{
|
||||
if (!flush_)
|
||||
return false;
|
||||
|
||||
if (!empty())
|
||||
return false;
|
||||
|
||||
flush_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
83
tjp/core/pipe/_tests/Pipe.cpp
Executable file
83
tjp/core/pipe/_tests/Pipe.cpp
Executable file
@@ -0,0 +1,83 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include <tjp/core/pipe/Pipe.h>
|
||||
|
||||
#include <tjp/core/algorithm/copy_of.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace test {
|
||||
|
||||
SCENARIO("audio pipe")
|
||||
{
|
||||
typedef std::vector<char> Packet;
|
||||
|
||||
Packet a({'a', 'a', 'a', 'a', 'a'});
|
||||
Packet b({'b', 'b', 'b' });
|
||||
|
||||
GIVEN("a pipe")
|
||||
{
|
||||
Pipe<Packet> p;
|
||||
REQUIRE(p.empty());
|
||||
|
||||
WHEN("write 1 packet")
|
||||
{
|
||||
p.write(core::copy_of(a));
|
||||
|
||||
REQUIRE(p.size() == a.size());
|
||||
REQUIRE(!p.empty());
|
||||
}
|
||||
|
||||
WHEN("write 2 packets")
|
||||
{
|
||||
p.write(core::copy_of(a));
|
||||
p.write(core::copy_of(b));
|
||||
|
||||
REQUIRE(p.size() == a.size() + b.size());
|
||||
}
|
||||
|
||||
WHEN("write 2 packets and read 1")
|
||||
{
|
||||
p.write(core::copy_of(a));
|
||||
p.write(core::copy_of(b));
|
||||
p.read();
|
||||
|
||||
REQUIRE(p.size() == b.size());
|
||||
}
|
||||
|
||||
WHEN("write 2 packets and read 2")
|
||||
{
|
||||
p.write(core::copy_of(a));
|
||||
p.write(core::copy_of(b));
|
||||
p.read();
|
||||
p.read();
|
||||
|
||||
REQUIRE(p.size() == 0);
|
||||
REQUIRE(p.empty());
|
||||
}
|
||||
|
||||
WHEN("write 2 packets and read some")
|
||||
{
|
||||
p.write(core::copy_of(a));
|
||||
p.write(core::copy_of(b));
|
||||
Packet u, v;
|
||||
u.resize(7);
|
||||
|
||||
v = a;
|
||||
v.insert(v.end(), b.begin(), b.end());
|
||||
v.resize(u.size());
|
||||
|
||||
p.read(u.data(), u.size());
|
||||
|
||||
REQUIRE(u == v);
|
||||
REQUIRE(p.size() == (a.size() + b.size() - u.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
173
tjp/core/pipe/obsolete/Pipe.cpp
Executable file
173
tjp/core/pipe/obsolete/Pipe.cpp
Executable file
@@ -0,0 +1,173 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include "Pipe.h"
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
Pipe::~Pipe ()
|
||||
{
|
||||
}
|
||||
|
||||
PipeStream::PipeStream ()
|
||||
{
|
||||
writing = reading = true;
|
||||
offset = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
PipeStream::~PipeStream ()
|
||||
{
|
||||
while (!buffers.empty())
|
||||
{
|
||||
delete[] buffers.front().first;
|
||||
buffers.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
bool PipeStream::isReading () const
|
||||
{
|
||||
return reading;
|
||||
}
|
||||
|
||||
bool PipeStream::isWriting () const
|
||||
{
|
||||
return writing;
|
||||
}
|
||||
|
||||
void PipeStream::write (const char *buffer, size_t size)
|
||||
{
|
||||
char *copy = new char[size];
|
||||
memcpy (copy, buffer, size);
|
||||
|
||||
buffers.push_back (std::pair<char *, size_t>(copy, size));
|
||||
this->size += size;
|
||||
}
|
||||
|
||||
void PipeStream::unread (const char *buffer, size_t size)
|
||||
{
|
||||
auto amountToWriteToExisting = std::min(offset, size);
|
||||
memcpy (buffers.front().first + (offset - amountToWriteToExisting), buffer + (size - amountToWriteToExisting), amountToWriteToExisting);
|
||||
|
||||
|
||||
auto amountToNewBuffer = size - amountToWriteToExisting;
|
||||
char *copy = new char[amountToNewBuffer];
|
||||
memcpy (copy, buffer, amountToNewBuffer);
|
||||
|
||||
buffers.push_front (std::pair<char *, size_t>(copy, amountToNewBuffer));
|
||||
this->size += size;
|
||||
}
|
||||
|
||||
char *PipeStream::write (size_t size)
|
||||
{
|
||||
char *copy = new char[size];
|
||||
buffers.push_back (std::pair<char *, size_t>(copy, size));
|
||||
this->size += size;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void PipeStream::closeWrite ()
|
||||
{
|
||||
writing = false;
|
||||
|
||||
if (!reading)
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PipeStream::closeRead ()
|
||||
{
|
||||
reading = false;
|
||||
|
||||
if (!writing)
|
||||
delete this;
|
||||
}
|
||||
|
||||
Pipe::size_t PipeStream::peek (char *buffer, size_t size) const
|
||||
{
|
||||
size_t ptr = 0;
|
||||
size_t offset = this->offset;
|
||||
|
||||
std::list< std::pair<char *, size_t> >::const_iterator i=buffers.begin();
|
||||
while (i!=buffers.end() && (size > 0))
|
||||
{
|
||||
auto chunksize = i->second - offset;
|
||||
size_t newoffset = 0;
|
||||
|
||||
if (chunksize > size)
|
||||
{
|
||||
newoffset = offset + size;
|
||||
chunksize = size;
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
memcpy (buffer + ptr, i->first + offset, chunksize);
|
||||
|
||||
ptr += chunksize;
|
||||
size -= chunksize;
|
||||
offset = newoffset;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
PipeStream::size_t PipeStream::read (char *buffer, size_t size)
|
||||
{
|
||||
size_t ptr = 0;
|
||||
|
||||
while (!buffers.empty() && (size > 0))
|
||||
{
|
||||
auto chunksize = buffers.front().second - offset;
|
||||
size_t newoffset = 0;
|
||||
|
||||
if (chunksize > size)
|
||||
{
|
||||
newoffset = offset + size;
|
||||
chunksize = size;
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
memcpy (buffer + ptr, buffers.front().first + offset, chunksize);
|
||||
|
||||
ptr += chunksize;
|
||||
size -= chunksize;
|
||||
offset = newoffset;
|
||||
|
||||
if (offset == 0)
|
||||
{
|
||||
delete[] buffers.front().first;
|
||||
buffers.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
this->size -= ptr;
|
||||
|
||||
return ptr;
|
||||
} ;
|
||||
|
||||
PipeStream::size_t PipeStream::getSize () const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
bool PipeStream::eos () const
|
||||
{
|
||||
return getSize() == 0 && !isWriting();
|
||||
}
|
||||
|
||||
void PipeStream::clear ()
|
||||
{
|
||||
while (!buffers.empty())
|
||||
{
|
||||
delete[] buffers.front().first;
|
||||
buffers.pop_front();
|
||||
}
|
||||
|
||||
size = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
102
tjp/core/pipe/obsolete/Pipe.h
Executable file
102
tjp/core/pipe/obsolete/Pipe.h
Executable file
@@ -0,0 +1,102 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
class Pipe
|
||||
{
|
||||
public:
|
||||
typedef ::size_t size_t;
|
||||
|
||||
virtual ~Pipe ();
|
||||
|
||||
virtual bool isReading () const = 0;
|
||||
virtual bool isWriting () const = 0;
|
||||
|
||||
virtual void write (const char *buffer, size_t size_t) = 0;
|
||||
virtual void closeWrite () = 0;
|
||||
|
||||
virtual size_t peek (char *buffer, size_t size_t) const = 0;
|
||||
virtual size_t read (char *buffer, size_t size_t) = 0;
|
||||
|
||||
int readChar ()
|
||||
{
|
||||
unsigned char c;
|
||||
auto size_t = read((char *)&c, 1);
|
||||
if (size_t != 1)
|
||||
return -1;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
virtual void closeRead () = 0;
|
||||
|
||||
virtual size_t getSize () const = 0;
|
||||
virtual bool eos () const = 0;
|
||||
|
||||
virtual void clear () = 0;
|
||||
} ;
|
||||
|
||||
class PipeStream : public Pipe
|
||||
{
|
||||
protected:
|
||||
bool reading, writing;
|
||||
std::list< std::pair<char *, size_t> > buffers;
|
||||
size_t offset, size;
|
||||
|
||||
public:
|
||||
PipeStream ();
|
||||
virtual ~PipeStream ();
|
||||
|
||||
virtual bool isReading () const;
|
||||
virtual bool isWriting () const;
|
||||
|
||||
virtual void write (const char *buffer, size_t size_t);
|
||||
virtual char *write(size_t size_t);
|
||||
virtual void closeWrite ();
|
||||
|
||||
virtual size_t peek (char *buffer, size_t size_t) const;
|
||||
|
||||
void unread (const char *buffer, size_t size_t);
|
||||
virtual size_t read (char *buffer, size_t size_t);
|
||||
virtual void closeRead ();
|
||||
|
||||
virtual size_t getSize () const;
|
||||
virtual bool eos () const;
|
||||
|
||||
virtual void clear ();
|
||||
} ;
|
||||
|
||||
class PacketStream
|
||||
{
|
||||
protected:
|
||||
bool reading, writing;
|
||||
std::list< std::vector<char> > buffers;
|
||||
|
||||
public:
|
||||
PacketStream ();
|
||||
virtual ~PacketStream ();
|
||||
|
||||
virtual void read (const char *buffer, size_t size_t);
|
||||
virtual char *write(size_t size_t);
|
||||
virtual void closeWrite ();
|
||||
|
||||
virtual size_t peek (char *buffer, size_t size_t) const;
|
||||
|
||||
void unread (const char *buffer, size_t size_t);
|
||||
virtual size_t read (char *buffer, size_t size_t);
|
||||
virtual void closeRead ();
|
||||
|
||||
virtual size_t getSize () const;
|
||||
virtual bool eos () const;
|
||||
|
||||
virtual void clear ();
|
||||
} ;
|
||||
|
||||
} // namespace core
|
||||
} // namespace tjp
|
||||
|
||||
Reference in New Issue
Block a user