2014/12/30

Lamba captures with move semantics in C++ 11

It is possible to move values into lambda's in C++ 11 but it requires a wrapper. Here is what I am using.  It should only be used in this context as when it is copied it acts like a move and sucks the guts out of the source. I needed this where I had to supply a shared_ptr to a class to an async event callback and needed to keep it in scope past the lifetime of the parent. I did not want to store the "global" and copying would keep the lifetime alive well past the end of the callback

template<typename T>
class MoveCapture {
mutable T m_value;
public:
MoveCapture( ) = delete;
MoveCapture( T && val ) : m_value( std::move( val ) ) { }
MoveCapture( MoveCapture const & other ) : m_value( std::move( other.m_value ) ) { }
MoveCapture& operator=(MoveCapture const & rhs) {
if( this != &rhs ) {
m_value = std::move( rhs.m_value );
}
return *this;
}
T& value( ) {
return m_value;
}
T const & value( ) const {
return m_value;
}
T& operator*() {
return m_value.operator*();
}
T const & operator*() const {
return m_value.operator*();
}
T const * operator->() const {
return m_value.operator->();
}
~MoveCapture( ) = default;
T move_out( ) {
auto result = std::move( m_value );
return result;
}
}; // class MoveCapture
template<typename T>
MoveCapture<T> as_move_only( T&& val ) {
return MoveCapture<T>( std::move( val ) );
}
////////////////////////////////
/// Example usage
int main( int, char** ) {
auto lots_of_data = std::vector<LargeObj>( 100000000 );
auto mlots_of_data = as_move_only( std::move( lots_of_data ) );
auto processed_data = [mlots_of_data](...) {
// do something
return mlots_of_data;
}( );
return 0;
}
Link

2014/12/13

A barebones async server with Boost ASIO

I am writing this partially for my own documentation.  Took me a few to jump through the examples on the Boost site, so I thought I would post a skeleton async server.
There are a couple of things to keep in mind. You own the buffers and must maintain their lifetime. I have done this by passing the connection to the handlers via a iterator/pointer. In the case of the write handler I pass a shared_ptr to the data buffer. Both methods should work. In more complicated servers there will be more than a buffer and socket to maintain in a connection. Also, the ioservice will block until there is no work available. That is it. So here is the Hello World async server
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <cstdint>
#include <iostream>
#include <list>
#include <memory>
struct Connection {
boost::asio::ip::tcp::socket socket;
boost::asio::streambuf read_buffer;
Connection( boost::asio::io_service & io_service ) : socket( io_service ), read_buffer( ) { }
Connection( boost::asio::io_service & io_service, size_t max_buffer_size ) : socket( io_service ), read_buffer( max_buffer_size ) { }
};
class Server {
boost::asio::io_service m_ioservice;
boost::asio::ip::tcp::acceptor m_acceptor;
std::list<Connection> m_connections;
using con_handle_t = std::list<Connection>::iterator;
public:
Server( ) : m_ioservice( ), m_acceptor( m_ioservice ), m_connections( ) { }
void handle_read( con_handle_t con_handle, boost::system::error_code const & err, size_t bytes_transfered ) {
if( bytes_transfered > 0 ) {
std::istream is( &con_handle->read_buffer );
std::string line;
std::getline( is, line );
std::cout << "Message Received: " << line << std::endl;
}
if( !err ) {
do_async_read( con_handle );
} else {
std::cerr << "We had an error: " << err.message( ) << std::endl;
m_connections.erase( con_handle );
}
}
void do_async_read( con_handle_t con_handle ) {
auto handler = boost::bind( &Server::handle_read, this, con_handle, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred );
boost::asio::async_read_until( con_handle->socket, con_handle->read_buffer, "\n", handler );
}
void handle_write( con_handle_t con_handle, std::shared_ptr<std::string> msg_buffer, boost::system::error_code const & err ) {
if( !err ) {
std::cout << "Finished sending message\n";
if( con_handle->socket.is_open( ) ) {
// Write completed successfully and connection is open
}
} else {
std::cerr << "We had an error: " << err.message( ) << std::endl;
m_connections.erase( con_handle );
}
}
void handle_accept( con_handle_t con_handle, boost::system::error_code const & err ) {
if( !err ) {
std::cout << "Connection from: " << con_handle->remote_endpoint( ).address( ).to_string( ) << "\n";
std::cout << "Sending message\n";
auto buff = std::make_shared<std::string>( "Hello World!\r\n\r\n" );
auto handler = boost::bind( &Server::handle_write, this, con_handle, buff, boost::asio::placeholders::error );
boost::asio::async_write( con_handle->socket, boost::asio::buffer( *buff ), handler );
do_async_read( con_handle );
} else {
std::cerr << "We had an error: " << err.message( ) << std::endl;
m_connections.erase( con_handle );
}
start_accept( );
}
void start_accept( ) {
auto con_handle = m_connections.emplace( m_connections.begin( ), m_ioservice );
auto handler = boost::bind( &Server::handle_accept, this, con_handle, boost::asio::placeholders::error );
m_acceptor.async_accept( con_handle->socket, handler );
}
void listen( uint16_t port ) {
auto endpoint = boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4( ), port );
m_acceptor.open( endpoint.protocol( ) );
m_acceptor.set_option( boost::asio::ip::tcp::acceptor::reuse_address( true ) );
m_acceptor.bind( endpoint );
m_acceptor.listen( );
start_accept( );
}
void run( ) {
m_ioservice.run( );
}
};
int main( int, char** ) {
auto srv = Server( );
srv.listen( 12345 );
srv.run( );
return 0;
}
Link

2012/12/07

Arduino Uno on Windows 8 without disabling driver signing

I tried to install my Arduino Uno under Windows 8 today.  The included drivers do not work because they are not signed.  One way people get them to work is to temporarily disable the check on driver signing as seen here.  I was able to do it without rebooting or using unsigned drivers.   Here is how:

  1. First plug in your Uno and let the driver installation fail.  
  2. Open the device manager, click start and then type device manager. 
  3. Right click on the yellow Arduino Uno and choose update driver software. 
  4. Click "Browse my computer for driver software"
  5. Then click "Let me pick from a list of device drivers on my computer"
  6. Click modem and then next.
  7. In the list, under manufactuer, choose Compaq.  Then for model choose "Ricochet Wireless USB Modem"
  8. When Windows complains, it is OK, choose to continue and the close the installer after it completes.
  9. Now under modems, you will see "Ricochet Wireless USB Modem", right click on it and choose properties.
  10. Under modem, set the maximum speed to 9600.
  11. On the advanced tab, click "Advanced Port Settings"
  12. Uncheck use FIFO buffers
  13. Note the COM Port Number, you will need this in the Arduino IDE
  14. Click OK, and click OK.
  15. Done

I was able to figure this out by looking at the existing Arduino Uno drivers and noted that they do not install a driver but provide device id's that use the usbser.sys.  I looked through c:\windows\inf and found this device uses the same driver.  Because it is a modem driver, Windows will treat it exactly like a COM port unless you try to use dialup software.  You most likely will not be dialing up with an Arduino.


2012/01/24

What am I reading about

Currently I am looking into image classification and how it relates to plants.  Whether it be a neural network approach with a human feedback or using a database of known's for training.  Probably a hybrid of the two.  This should allow autonomous devices to classify plants and insects that belong or do not belong or are unknown.

2009/11/03

Quicky: Multiple compilers means less debugging

I've been at the C++ game the past view days and we all have seen those nasty STL errors that don't give you a clue as to what the problem is. Such as

Error 1 error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'

I have found that compiling under multiple compilers will give you just enough info to actually find the error. In my case I was trying to add a std::fstream to a std::vector. So the error was technically correct, but didn't indicate that you cannot do that.

2009/11/01

Trying to build cross platform software isn't always easy

Trying to build cross platform software isn't always easy. For instance, the truncate function that exists on Linux and part of the unistd.h header does not exist under Windows unless you use cygwin. Windows does have the SetFilePointer to set the position and SetEndOfFile functions. You can now build a truncate function and wrap it in a #ifdef WIN32 ... #endif and it will only be used under windows.

Here is currently what I am using. Needs a bit more error checking but you can get the gist of it:


#ifdef WIN32 // Not defined in windows, translated to use SetEndOfFile function
int truncate( const char *path, const long long &length ) {
HANDLE hFile = CreateFileA( path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
LARGE_INTEGER li;
li.QuadPart = length;
int ret = -1;
if( SetFilePointer( hFile, li.LowPart, &li.HighPart, FILE_BEGIN ) != INVALID_SET_FILE_POINTER ) {
SetEndOfFile( hFile );
ret = 0;
}
CloseHandle( hFile );
return ret;
}
#endif