Setting a bit
Use the bitwise OR operator (|
) to set a bit.
number |= 1UL << n;
That will set the n
th bit of number
. n
should be zero, if you want to set the 1
st bit and so on upto n-1
, if you want to set the n
th bit.
Use 1ULL
if number
is wider than unsigned long
; promotion of 1UL << n
doesn't happen until after evaluating 1UL << n
where it's undefined behaviour to shift by more than the width of a long
. The same applies to all the rest of the examples.
Clearing a bit
Use the bitwise AND operator (&
) to clear a bit.
number &= ~(1UL << n);
That will clear the n
th bit of number
. You must invert the bit string with the bitwise NOT operator (~
), then AND it.
Toggling a bit
The XOR operator (^
) can be used to toggle a bit.
number ^= 1UL << n;
That will toggle the n
th bit of number
.
Checking a bit
You didn't ask for this, but I might as well add it.
To check a bit, shift the number n to the right, then bitwise AND it:
bit = (number >> n) & 1U;
That will put the value of the n
th bit of number
into the variable bit
.
Changing the nth bit to x
Setting the n
th bit to either 1
or 0
can be achieved with the following on a 2's complement C++ implementation:
number ^= (-x ^ number) & (1UL << n);
Bit n
will be set if x
is 1
, and cleared if x
is 0
. If x
has some other value, you get garbage. x = !!x
will booleanize it to 0 or 1.
To make this independent of 2's complement negation behaviour (where -1
has all bits set, unlike on a 1's complement or sign/magnitude C++ implementation), use unsigned negation.
number ^= (-(unsigned long)x ^ number) & (1UL << n);
or
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
It's generally a good idea to use unsigned types for portable bit manipulation.
or
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
will clear the n
th bit and (x << n)
will set the n
th bit to x
.
It's also generally a good idea to not to copy/paste code in general and so many people use preprocessor macros (like the community wiki answer further down) or some sort of encapsulation.
The compiler is allowed to make one implicit conversion to resolve the parameters to a function. What this means is that the compiler can use constructors callable with a single parameter to convert from one type to another in order to get the right type for a parameter.
Here's an example class with a constructor that can be used for implicit conversions:
class Foo
{
public:
// single parameter constructor, can be used as an implicit conversion
Foo (int foo) : m_foo (foo)
{
}
int GetFoo () { return m_foo; }
private:
int m_foo;
};
Here's a simple function that takes a Foo
object:
void DoBar (Foo foo)
{
int i = foo.GetFoo ();
}
and here's where the DoBar
function is called:
int main ()
{
DoBar (42);
}
The argument is not a Foo
object, but an int
. However, there exists a constructor for Foo
that takes an int
so this constructor can be used to convert the parameter to the correct type.
The compiler is allowed to do this once for each parameter.
Prefixing the explicit
keyword to the constructor prevents the compiler from using that constructor for implicit conversions. Adding it to the above class will create a compiler error at the function call DoBar (42)
. It is now necessary to call for conversion explicitly with DoBar (Foo (42))
The reason you might want to do this is to avoid accidental construction that can hide bugs.
Contrived example:
- You have a
MyString
class with a constructor that constructs a string of the given size. You have a function print(const MyString&)
(as well as an overload print (char *string)
), and you call print(3)
(when you actually intended to call print("3")
). You expect it to print "3", but it prints an empty string of length 3 instead.
Best Solution
Scope
Boost.Asio is a C++ library that started with a focus on networking, but its asynchronous I/O capabilities have been extended to other resources. Additionally, with Boost.Asio being part of the Boost libraries, its scope is slightly narrowed to prevent duplication with other Boost libraries. For example, Boost.Asio will not provide a thread abstraction, as Boost.Thread already provides one.
On the other hand, libuv is a C library designed to be the platform layer for Node.js. It provides an abstraction for IOCP on Windows, kqueue on macOS, and epoll on Linux. Additionally, it looks as though its scope has increased slightly to include abstractions and functionality, such as threads, threadpools, and inter-thread communication.
At their core, each library provides an event loop and asynchronous I/O capabilities. They have overlap for some of the basic features, such as timers, sockets, and asynchronous operations. libuv has a broader scope, and provides additional functionality, such as thread and synchronization abstractions, synchronous and asynchronous file system operations, process management, etc. In contrast, Boost.Asio's original networking focus surfaces, as it provides a richer set of network related capabilities, such as ICMP, SSL, synchronous blocking and non-blocking operations, and higher-level operations for common tasks, including reading from a stream until a newline is received.
Feature List
Here is the brief side-by-side comparison on some of the major features. Since developers using Boost.Asio often have other Boost libraries available, I have opted to consider additional Boost libraries if they are either directly provided or trivial to implement.
1. Scatter/Gather I/O.
2. Boost.Extension was never submitted for review to Boost. As noted here, the author considers it to be complete.
Event Loop
While both libuv and Boost.Asio provide event loops, there are some subtle differences between the two:
uv_default_loop()
), rather than creating a new loop (uv_loop_new()
), as another component may be running the default loop.io_service
are their own loops that allow for multiple threads to run. To support this Boost.Asio performs internal locking at the cost of some performance. Boost.Asio's revision history indicates that there have been several performance improvements to minimize the locking.Threadpool
uv_queue_work
. The threadpool size is configurable via the environment variableUV_THREADPOOL_SIZE
. The work will be executed outside of the event loop and within the threadpool. Once the work is completed, the completion handler will be queued to run within the event loop.io_service
can easily function as one as a result ofio_service
allowing multiple threads to invokerun
. This places the responsibility of thread management and behavior to the user, as can be seen in this example.Threading and Synchronization
File System Operations
Networking
EAGAIN
orEWOULDBLOCK
.Signal
kill
and signal handling with itsuv_signal_t
type anduv_signal_*
operations.kill
, but itssignal_set
provides signal handling.IPC
uv_pipe_t
type.local::stream_protocol::socket
orlocal::datagram_protocol::socket
, andwindows::stream_handle
.API Differences
While the APIs are different based on the language alone, here are a few key differences:
Operation and Handler Association
Within Boost.Asio, there is a one-to-one mapping between an operation and a handler. For instance, each
async_write
operation will invoke the WriteHandler once. This is true for many of libuv operations and handlers. However, libuv'suv_async_send
supports a many-to-one mapping. Multipleuv_async_send
calls may result in the uv_async_cb being called once.Call Chains vs. Watcher Loops
When dealing with task, such as reading from a stream/UDP, handling signals, or waiting on timers, Boost.Asio's asynchronous call chains are a bit more explicit. With libuv, a watcher is created to designate interests in a particular event. A loop is then started for the watcher, where a callback is provided. Upon receiving the event of interests, the callback will be invoked. On the other hand, Boost.Asio requires an operation to be issued each time the application is interested in handling the event.
To help illustrate this difference, here is an asynchronous read loop with Boost.Asio, where the
async_receive
call will be issued multiple times:And here is the same example with libuv, where
handle_read
is invoked each time the watcher observes that the socket has data:Memory Allocation
As a result of the asynchronous call chains in Boost.Asio and the watchers in libuv, memory allocation often occurs at different times. With watchers, libuv defers allocation until after it receives an event that requires memory to handle. The allocation is done through a user callback, invoked internal to libuv, and defers deallocation responsibility of the application. On the other hand, many of the Boost.Asio operations require that the memory be allocated before issuing the asynchronous operation, such as the case of the
buffer
forasync_read
. Boost.Asio does providenull_buffers
, that can be used to listen for an event, allowing applications to defer memory allocation until memory is needed, although this is deprecated.This memory allocation difference also presents itself within the
bind->listen->accept
loop. With libuv,uv_listen
creates an event loop that will invoke the user callback when a connection is ready to be accepted. This allows the application to defer the allocation of the client until a connection is being attempted. On the other hand, Boost.Asio'slisten
only changes the state of theacceptor
. Theasync_accept
listens for the connection event, and requires the peer to be allocated before being invoked.Performance
Unfortunately, I do not have any concrete benchmark numbers to compare libuv and Boost.Asio. However, I have observed similar performance using the libraries in real-time and near-real-time applications. If hard numbers are desired, libuv's benchmark test may serve as a starting point.
Additionally, while profiling should be done to identify actual bottlenecks, be aware of memory allocations. For libuv, the memory allocation strategy is primarily limited to the allocator callback. On the other hand, Boost.Asio's API does not allow for an allocator callback, and instead pushes the allocation strategy to the application. However, the handlers/callbacks in Boost.Asio may be copied, allocated, and deallocated. Boost.Asio allows for applications to provide custom memory allocation functions in order to implement a memory allocation strategy for handlers.
Maturity
Boost.Asio
Asio's development dates back to at least OCT-2004, and it was accepted into Boost 1.35 on 22-MAR-2006 after undergoing a 20-day peer review. It also served as the reference implementation and API for Networking Library Proposal for TR2. Boost.Asio has a fair amount of documentation, although its usefulness varies from user to user.
The API also have a fairly consistent feel. Additionally, the asynchronous operations are explicit in the operation's name. For example,
accept
is synchronous blocking andasync_accept
is asynchronous. The API provides free functions for common I/O task, for instance, reading from a stream until a\r\n
is read. Attention has also been given to hide some network specific details, such as theip::address_v4::any()
representing the "all interfaces" address of0.0.0.0
.Finally, Boost 1.47+ provides handler tracking, which can prove to be useful when debugging, as well as C++11 support.
libuv
Based on their github graphs, Node.js's development dates back to at least FEB-2009, and libuv's development dates to MAR-2011. The uvbook is a great place for a libuv introduction. The API documentation is here.
Overall, the API is fairly consistent and easy to use. One anomaly that may be a source of confusion is that
uv_tcp_listen
creates a watcher loop. This is different than other watchers that generally have auv_*_start
anduv_*_stop
pair of functions to control the life of the watcher loop. Also, some of theuv_fs_*
operations have a decent amount of arguments (up to 7). With the synchronous and asynchronous behavior being determined on the presence of a callback (the last argument), the visibility of the synchronous behavior can be diminished.Finally, a quick glance at the libuv commit history shows that the developers are very active.