Split cpp a lot

This commit is contained in:
Ciro Santilli 2015-06-17 11:59:28 +02:00
parent bc46513a2b
commit a91befb3d6
44 changed files with 2873 additions and 2694 deletions

View File

@ -9,14 +9,15 @@
MYCC ?= gcc
MYCXX ?= g++
D ?= #-D_XOPEN_SOURCE 700
G ?= gdb3
I ?= #-I/usr/include
O ?= 0
STD ?= c11
PEDANTIC ?= -pedantic-errors
CFLAGS ?= $(D) -O$(O) -std=$(STD) -Wextra $(PEDANTIC) $(CFLAGS_EXTRA)
MYCXXFLAGS ?= $(D) -O$(O) -std=c++11 -Wextra $(PEDANTIC) $(CXXFLAGS_EXTRA)
CFLAGS ?= $(D) -g$(G) -O$(O) -std=$(STD) -Wextra $(PEDANTIC) $(CFLAGS_EXTRA)
MYCXXFLAGS ?= $(D) -g$(G) -O$(O) -std=c++11 -Wextra $(PEDANTIC) $(CXXFLAGS_EXTRA)
LIBS ?= -lm #-lGL -lGLU -lglut
LIBS ?= -lm -pthread #-lGL -lGLU -lglut
# Fortran
FF ?= gfortran
@ -40,10 +41,6 @@ RUN_INPUT ?= input
TEST ?= test
ASSEMBLER_NOEXT ?= $(IN_DIR)$(RUN)
DEBUG_DEFINE ?=
DEBUG_FLAGS ?=
PROFILE_DEFINE ?= #-DDEBUG
PROFILE_FLAGS ?= #
RUN_BNAME := $(RUN)$(OUT_EXT)
@ -53,7 +50,7 @@ OUTS_NODIR := $(basename $(INS_NODIR))
OUTS_NODIR := $(addsuffix $(OUT_EXT), $(OUTS_NODIR))
OUTS := $(addprefix $(OUT_DIR), $(OUTS_NODIR))
.PHONY: all asm set_asm_flags clean debug set_debug_flags help mkdir objdump set_objdump_flags profile set_profile_flags test $(PHONY)
.PHONY: all asm clean debug help mkdir objdump set_objdump_flags profile set_profile_flags test $(PHONY)
all: mkdir $(OUTS)
@#TODO ignore errors if not present
@ -65,26 +62,26 @@ ifneq ($(strip $(run)),)
endif
$(OUT_DIR)%$(OUT_EXT): $(IN_DIR)%.c
$(MYCC) $(CFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(DEBUG_DEFINE) $(DEBUG_FLAGS) $(I) -o "$@" "$<" $(LIBS)
$(MYCC) $(CFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(I) -o "$@" "$<" $(LIBS)
$(OUT_DIR)%$(OUT_EXT): $(IN_DIR)%.cpp
$(MYCXX) $(MYCXXFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(DEBUG_DEFINE) $(DEBUG_FLAGS) $(I) -o "$@" "$<" $(LIBS)
$(MYCXX) $(MYCXXFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(I) -o "$@" "$<" $(LIBS)
$(OUT_DIR)%$(OUT_EXT): $(IN_DIR)%.f
$(FF) $(FFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(DEBUG_DEFINE) $(DEBUG_FLAGS) -o "$@" "$<" $(FFLIBS)
$(FF) $(FFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) -o "$@" "$<" $(FFLIBS)
# Make assembly intermingled with original C code to stdout>
# TODO0: how not to rewrite the make rules?
# For bare asm: $(MYCC) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(DEBUG_DEFINE) $(DEBUG_FLAGS) $(CFLAGS) -fverbose-asm -S "$(ASSEMBLER_NOEXT)$$EXT"
# For bare asm: $(MYCC) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(CFLAGS) -fverbose-asm -S "$(ASSEMBLER_NOEXT)$$EXT"
asm: mkdir set_asm_flags
for EXT in $(IN_EXTS); do \
if [ -f "$(ASSEMBLER_NOEXT)$$EXT" ]; then \
case "$$EXT" in \
.c)\
$(MYCC) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(DEBUG_DEFINE) $(DEBUG_FLAGS) $(CFLAGS) -c -fverbose-asm -Wa,-adhln "$(ASSEMBLER_NOEXT)$$EXT" $(LIBS) -o $(OUT_DIR)asm.o\
$(MYCC) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(CFLAGS) -c -fverbose-asm -Wa,-adhln "$(ASSEMBLER_NOEXT)$$EXT" $(LIBS) -o $(OUT_DIR)asm.o\
;;\
.cpp)\
$(MYCXX) $(MYCXXFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) $(DEBUG_DEFINE) $(DEBUG_FLAGS) -c -fverbose-asm -Wa,-adhln "$(ASSEMBLER_NOEXT)$$EXT" $(LIBS)\
$(MYCXX) $(MYCXXFLAGS) $(PROFILE_DEFINE) $(PROFILE_FLAGS) -c -fverbose-asm -Wa,-adhln "$(ASSEMBLER_NOEXT)$$EXT" $(LIBS)\
;;\
.f)\
;;\
@ -93,9 +90,6 @@ asm: mkdir set_asm_flags
fi;\
done
set_asm_flags:
$(eval DEBUG_FLAGS := -ggdb3)
clean:
if [ ! '$(OUT_DIR)' = './' ]; then \
rm -rf '$(OUT_DIR)' ;\
@ -106,21 +100,14 @@ clean:
debug: clean set_debug_flags all
cd $(OUT_DIR) && gdb "$(RUN_BNAME)"
set_debug_flags:
$(eval DEBUG_FLAGS := -ggdb3)
$(eval DEBUG_DEFINE := -DDEBUG)
mkdir:
@mkdir -p "$(OUT_DIR)"
objdump: mkdir set_objdump_flags all
cd $(OUT_DIR) && objdump -S $(RUN_BNAME)
set_objdump_flags:
$(eval DEBUG_FLAGS := -ggdb3)
cd '$(OUT_DIR)' && objdump -CSr '$(RUN_BNAME)'
profile: clean set_profile_flags all run
cd $(OUT_DIR) && gprof -b $(RUN_BNAME) gmon.out | tee "$(RUN_BNAME).profile_out" | less
cd '$(OUT_DIR)' && gprof -b '$(RUN_BNAME)' gmon.out | tee "$(RUN_BNAME).profile_out" | less
run: all
@echo

View File

@ -41,6 +41,7 @@ int main() {
/*, E5*/
};
/* Enum types can then be cast to int. */
/* If unspecified, the first is 0. */
assert(E0 == 0);
assert(E1 == 1);
@ -48,6 +49,19 @@ int main() {
/* Continue from the last one. */
assert(E3 == 4);
assert(E4 == INT_MAX);
// int can also be cast to enum?
{
{
enum E e = 0;
assert(e == E0);
}
{
enum E e = -1;
assert(e == -1);
}
}
}
/*

1
c/posix/Makefile Symbolic link
View File

@ -0,0 +1 @@
../Makefile

3
c/posix/README.md Normal file
View File

@ -0,0 +1,3 @@
# POSIX
C features which require POSIX to demonstrate, possibly because some parts haven't been implemented yet, mainly multi-threading for now.

78
c/posix/atomic.c Normal file
View File

@ -0,0 +1,78 @@
/*
Optional language feature, checked with `__STDC_NO_ATOMICS__`.
Modeled on C++ `std::atomic` and analogous to it, just without using C++ language features.
# _Atomic
- http://stackoverflow.com/questions/24557728/does-any-c-library-implement-c11-threads-for-gnu-linux
# ATOMIC_VAR_INIT
Required to initialize auto `_Atomic`, but not globals
- http://stackoverflow.com/questions/15317666/how-to-initialize-and-use-a-c11-atomic-variable
*/
#ifndef __STDC_NO_ATOMICS__
#include <assert.h>
#include <pthread.h>
/* Not in GCC 5.1 yet. */
/*#include <threads.h>*/
#include <stdlib.h>
enum CONSTANTS {
NUM_THREADS = 1000,
NUM_ITERS = 1000
};
_Atomic int global = 0;
void* main_thread(void *arg) {
int i;
for (i = 0; i < NUM_ITERS; ++i) {
/*
Postrix ++ and compound assignment are atomic. TODO Other operators?
Other operations need `stdatomic` functions.
6.5.2.4/2 "Postfix increment and decrement operators"
> Postfix ++ on an object with atomic type is a read-modify-write operation
with memory_order_seq_cst memory order semantics.
6.5.16.2/3 "Compound assignment":
> If E1 has an atomic type, compound assignment is a read-modify-write operation
with memory_order_seq_cst memory order semantics.
*/
global++;
}
return NULL;
}
#endif
int main() {
#ifndef __STDC_NO_ATOMICS__
int i;
pthread_t threads[NUM_THREADS];
for (i = 0; i < NUM_THREADS; ++i)
pthread_create(&threads[i], NULL, main_thread, NULL);
for (i = 0; i < NUM_THREADS; ++i)
pthread_join(threads[i], NULL);
/* Not in GCC 5.1 yet. */
/*
thrd_t thr[NUM_THREADS];
for(int i = 0; n < NUM_THREADS; ++n)
thrd_create(&thr[i], main_thread, NULL);
for(int n = 0; n < NUM_THREADS; ++n)
thrd_join(thr[i], NULL);
*/
/* If we still had many threads here, I think we would need to use `atomic_load`. */
assert(global == NUM_THREADS * NUM_ITERS);
#endif
return EXIT_SUCCESS;
}

View File

@ -568,6 +568,14 @@ assert(false);
assert(sizeof(double) == 8);
#endif
}
#ifndef __STDC_NO_ATOMICS__
/* Indicates no C11 support for `_Atomic` and `<stdatomic.h>`. */
puts("__STDC_NO_ATOMICS__");
#else
#include <stdatomic.h>
_Atomic int i;
#endif
}
return EXIT_SUCCESS;

View File

@ -8,10 +8,15 @@
1. [main.cpp](main.cpp)
1. [Hello world](hello_world.cpp)
1. [const](const.cpp)
1. [RTTI](rtti.md)
1. Compile time magic
1. [constexpr](constexpr.cpp)
1. [static_assert](static_assert.cpp)
1. [typeid](typeid.cpp)
1. [auto](auto.cpp)
1. [decltype](decltype.cpp)
1. [nullptr](nullptr.cpp)
1. References
1. [reference](reference.cpp)
1. [rvalue reference](rvalue_reference.cpp)
1. [Function](function.cpp)
@ -29,10 +34,25 @@
1. [Preprocessor](preprocessor.cpp)
1. [Standard library](standard_library.md)
1. [Headers](common.hpp)
1. [limits](limits.cpp)
1. [Containers](containers.md)
1. [vector](vector.cpp)
1. [list](list.cpp)
1. [map](map.cpp)
1. [set](set.cpp)
1. [valarray](valarray.cpp)
1. [deque](deque.cpp)
1. [string](string.cpp)
1. [thread](thread.cpp)
1. [sleep_for](sleep_for.cpp)
1. [atomic](atomic.cpp)
1. [atomic<bool>](atomic_bool.cpp.off)
1. [mutex](mutex.cpp)
1. [algorithm](algorithm.cpp)
1. [functional](functional.cpp)
1. [iterator](iterator.cpp)
1. [limits](limits.cpp)
1. [memory](memory.cpp)
1. [regex](regex.cpp)
1. [utility](utility.cpp)
1. Applications
1. [Design patterns](design_patterns.cpp)

356
cpp/algorithm.cpp Normal file
View File

@ -0,0 +1,356 @@
/*
# algorithm
*/
#include "common.hpp"
int main() {
{
assert(std::min(0.1, 0.2) == 0.1);
assert(std::max(0.1, 0.2) == 0.2);
}
// # sort
{
std::vector<int> v{2, 0, 1};
std::sort(v.begin(), v.end());
std::vector<int> v1 = {0, 1, 2};
assert((v == std::vector<int>{0, 1, 2}));
}
// # reverse
{
std::vector<int> v{2, 0, 1};
std::reverse(v.begin(), v.end());
assert((v == std::vector<int>{1, 0, 2}));
}
/*
# swap
Does things equivalent to:
template <class T> void swap (T& a, T& b)
{
T c(a); a=b; b=c;
}
However stdlib can specialize it to do operations more efficiently.
Some stdlib classes implement swap as a method.
Particularly important because of the copy and swap idiom.
*/
// # randomize
{
std::vector<int> v{2, 0, 1};
std::random_shuffle(v.begin(), v.end());
}
// # copy
{
std::vector<int> v{2, 0, 1};
std::vector<int> v2(5, 3);
std::copy(v.begin(), v.end(), v2.begin() + 1);
assert(v2 == std::vector<int>({3, 2, 0, 1, 3}));
}
/*
# equal
Compares ranges of two containers.
*/
{
std::vector<int> v {0, 1, 2 };
std::vector<int> v2{ 1, 2, 3};
assert(std::equal(v.begin() + 1, v.end(), v2.begin()));
}
/*
# accumulate
Sum over range with operator+
Also has functional versions http://www.cplusplus.com/reference/numeric/accumulate/
*/
{
{
std::vector<int> v{2, 0, 1};
assert(std::accumulate(v.begin(), v.end(), 0) == 3);
assert(std::accumulate(v.begin(), v.end(), 10) == 13);
}
// The functional version can be used to add up arrays.
// http://stackoverflow.com/questions/26941943/how-to-add-all-numbers-in-an-array-c
{
int a[] = {1, 3, 5, 7, 9};
assert(std::accumulate(std::begin(a), std::end(a), 0, std::plus<int>()) == 25);
}
}
/*
# find
Return iterator to first found element.
*/
{
std::vector<int> v{2,0,1};
unsigned int pos;
pos = std::find(v.begin(), v.end(), 0) - v.begin();
assert(pos == 1);
pos = std::find(v.begin(), v.end(), 1) - v.begin();
assert(pos == 2);
pos = std::find(v.begin(), v.end(), 2) - v.begin();
assert(pos == 0);
pos = std::find(v.begin(), v.end(), 3) - v.begin(); //end() returned
assert(pos == v.size());
}
/*
# find_if
Like find, but using an arbitrary condition on each element instead of equality.
Consider usage with C++11 lambdas and functional.
*/
{
std::vector<int> v{2, 0, 1};
assert(std::find_if (v.begin(), v.end(), odd) == --v.end());
}
/*
# binary_search
Container must be already sorted.
Log complexity.
Only states if the element is present or not, but does not get its position.
If you want to get the position of those items, use `equal_range`, `lower_bound` or `upper_bound`.
*/
{
std::vector<int> v{0, 1, 2};
assert(std::binary_search(v.begin(), v.end(), 1) == true);
assert(std::binary_search(v.begin(), v.end(), 3) == false);
assert(std::binary_search(v.begin(), v.end() - 1, 2) == false);
}
/*
# lower_bound
Finds first element in container which is not less than val.
*/
{
std::vector<int> v{0, 2, 3};
auto it = std::lower_bound(v.begin(), v.end(), 1);
assert(it - v.begin() == 1);
}
/*
# upper_bound
Finds first element in container is greater than val.
*/
{
std::vector<int> v{0, 1, 2};
auto it = std::upper_bound(v.begin(), v.end(), 1);
assert(it - v.begin() == 2);
}
/*
# equal_range
Finds first and last location of a value iniside a ranged container.
Return values are the same as lower_bound and upper_bound.
log complexity.
*/
{
std::vector<int> v{0, 1, 1, 2};
std::vector<int>::iterator begin, end;
std::tie(begin, end) = std::equal_range(v.begin(), v.end(), 1);
assert(begin - v.begin() == 1);
assert(end - v.begin() == 3);
}
// # count
{
std::vector<int> v{2,1,2};
assert(std::count(v.begin(), v.end(), 0) == 0);
assert(std::count(v.begin(), v.end(), 1) == 1);
assert(std::count(v.begin(), v.end(), 2) == 2);
}
// # max_element #min_element
{
std::vector<int> v{2,0,1};
assert(*std::max_element(v.begin(), v.end()) == 2);
assert(*std::min_element(v.begin(), v.end()) == 0);
}
/*
# advance
Advance iterator by given number.
If random access, simply adds + N.
Else, calls `++` N times.
Advantage over `+`: only random access containers support `+`,
but this works for any container, allowing one to write more general code.
Beware however that this operation will be slow for non random access containers.
*/
{
std::vector<int> v{0, 1, 2};
auto it = v.begin();
std::advance(it, 2);
assert(*it == 2);
}
#if __cplusplus >= 201103L
/*
# next
Same as advance, but returns a new iterator instead of modifying the old one.
*/
{
std::vector<int> v{0, 1, 2};
auto it(v.begin());
auto itNext = std::next(it, 2);
assert(*it == 0);
assert(*itNext == 2);
}
#endif
/*
# priority queue
Offers `O(1)` access to the smalles element.
Other operatoins vary between `O(n)` and `O(1).
Most common implementaions are via:
- binary heap
- fibonacci heap
Boost offers explicit heap types: fibonacci, binary and others.
But no guarantees are made.
As of C++11, does not support the increase key operation.
A binary heap without increase key can be implemented via the heap function family under algorithm.
*/
/*
# heap
Binary heap implementation.
<http://en.wikipedia.org/wiki/Heap_%28data_structure%29>
In short:
- getting largest element is O(1)
- removing the largest element is O(lg) for all implementation
- other operations (insertion) may be O(1) or O(lg) depending on the implementation.
this makes for a good priority queue.
Exact heap type is not guaranteed. As of 2013, it seems that most implementations use binary heaps.
For specific heaps such as Fibonacci, consider [Boost](http://www.boost.org/doc/libs/1_49_0/doc/html/heap.html).
<http://stackoverflow.com/questions/14118367/stl-for-fibonacci-heap>
There is no concrete heap data structure in C++:
only heap operations over random access data structures.
This is why this is under algoritms and is not a data structure of its own.
There is however a `priority_queue` stdlib container.
Why random access structure is needed: <https://github.com/cirosantilli/comp-sci/blob/1.0/src/heap.md#array-implementation>
*/
{
int myints[]{10, 20, 30, 5, 15};
std::vector<int> v(myints, myints + 5);
/*
# make_heap
Make random access data structure into a heap.
This changes the element order so that the range has heap properties
Worst case time: $O(n)$.
*/
std::make_heap(v.begin(), v.end());
assert(v.front() == 30);
/*
# pop_heap
Remove the largest element from the heap.
That element is moved to the end of the data structure, but since the
heap should have its length reduced by one, that element will then be out of the heap.
Assumes that the input range is already a heap (made with `make_heap` for example).
*/
std::pop_heap(v.begin(), v.end());
//the element still exists on the data structure
assert(v.back() == 30);
//the second largest element hat become the largets
assert(v.front() == 20);
//remove the element from the data structure definitively
v.pop_back();
/*
# push_heap
Insert element into a heap.
Assumes that:
- the range 0 - (end - 1) was already a heap
- the new element to be inserted into that heap is at end.
*/
//add the new element to the data structure
v.push_back(99);
//reorganize the data so that the last element will be placed in the heap
std::push_heap(v.begin(), v.end());
assert(v.front() == 99);
/*
# sort_heap
Assumes that the input range is a heap, and sorts it in increasing order.
The assumption that we have a heap allows for $O(ln)$ sorting,
much faster than the optimal bound $O(n log n)$.
This is exactly what the heapsort alrotithm does: make_heap and then sort_heap.
*/
std::sort_heap(v.begin(), v.end());
//assert(v)
//v == 5 10 15 20 99
}
}

View File

@ -4,15 +4,16 @@
More restricted than mutex as it can only protect a few operations on integers.
But if that is the use case, may be more efficient.
On GCC 4.8 x86-64, using atomic is a huge peformance improvement
over the same program with mutexes (5x).
*/
#include "common.hpp"
#if __cplusplus >= 201103L
const int NUM_THREADS = 1000;
const int NUM_ITERS = 1000;
std::atomic_int global(0);
std::atomic_long global(0);
void threadMain() {
for (int i = 0; i < NUM_ITERS; ++i) {
@ -25,17 +26,11 @@ int main() {
#if __cplusplus >= 201103L
std::thread threads[NUM_THREADS];
int i;
for (i = 0; i < NUM_THREADS; ++i) {
for (i = 0; i < NUM_THREADS; ++i)
threads[i] = std::thread(threadMain);
}
for (i = 0; i < NUM_THREADS; ++i) {
for (i = 0; i < NUM_THREADS; ++i)
threads[i].join();
}
assert(global.load() == NUM_THREADS * NUM_ITERS);
// Same as above through `operator T`.
assert(global == NUM_THREADS * NUM_ITERS);
#endif

24
cpp/atomic_bool.cpp.off Normal file
View File

@ -0,0 +1,24 @@
/*
# atomic<bool>
bool is not considered as integral in C++11
You have to use other alternatives for the operations.
http://stackoverflow.com/questions/30254582/c-stdatomicboolfetch-or-not-implemented
*/
#include "common.hpp"
class myclass {
volatile std::atomic<int> flag;
public:
myclass(): flag(false) {}
bool get_flag() { return flag; }
bool try_set() {
return !flag.fetch_or(1);
}
void reset() {
flag = false;
}
};

32
cpp/attributes.cpp Normal file
View File

@ -0,0 +1,32 @@
/*
# Attributes
C++11 introduces a generalized attribute syntax.
Similar syntaxes have been rmplemented as extensions for a long time in GCC via `__attribtes__`
and in Microsoft with `#pragma`. Now some have been standardized!
Intended only for functions which don't change behaviour: only to help
compilers optimize or geneate better error messages.
http://www.stroustrup.com/C++11FAQ.html#attributes
Attributes can be defined for various objects, and there are 2 standard ones:
`noreturn` and `carries_dependency`
C11 also has some attributes like `_Noreturn`, but no generalized syntax.
*/
#include "common.hpp"
#if __cplusplus >= 201103L
void noreturn_func [[ noreturn ]] () { throw 1; }
#endif
int main() {
#if __cplusplus >= 201103L
try {
noreturn_func();
} catch (int i) {}
#endif
}

View File

@ -27,7 +27,6 @@
#include <new> //
#include <numeric> // partial sums, differences on std::vectors of numbers
#include <ostream> // ostream
#include <regex> //
#include <set> // multiset, set
#include <string> // getline, string
#include <sstream> // stringstream
@ -35,13 +34,14 @@
#include <tuple> // tuple
#include <unordered_map> // unordered_map, unordered_multimap
#include <utility> // forward, get, pair, size_t, type_info
#include <vector>
#include <vector> // vector
#include <valarray>
#if __cplusplus >= 201103L
#include <array> // array
#include <chrono> // nanoseconds
#include <mutex> // mutex
#include <regex> // regex
#include <thread> // thread
#include <typeindex> // type_index
#endif
@ -76,9 +76,17 @@
// Keeps a list of functions that called it for testing purposes.
static std::vector<std::string> callStack;
void printCallStack() {
static void printCallStack() {
std::cout << "callStack:" << std::endl;
for (auto& s : callStack)
std::cout << s << std::endl;
std::cout << "END callStack" << std::endl;
}
// Global thread parameters.
static const int NUM_THREADS = 1000;
static const int NUM_ITERS = 1000;
static const int NUM_OPS = NUM_THREADS * NUM_ITERS;
// Misc.
static bool odd(int i){ return (i % 2) == 1; }

18
cpp/containers.md Normal file
View File

@ -0,0 +1,18 @@
# Containers
The stdlib furnishes several containers.
It is a very important part of an algorithm to choose the right container for the task.
As of C++11, most containers are abstract, that is, only specify which operations it supports.
For example, a `UnorderedMap` could be implemented both as a hash map or a RB tree concrete data structures, but is always supports the same operations: insert, remove, and so on.
The major data structures which you must know about in order of decreasing usefulness are:
- std::vector
- set
- map
- list
- deque
- heap and priority queue

23
cpp/deque.cpp Normal file
View File

@ -0,0 +1,23 @@
/*
# deque
Double ended queue.
Random access.
Very similar interface to std::vector, except that:
- insertion to front is O(1)
- there is no guarantee of inner storage contiguity
Discussion on when to use deque or std::vector:
http://stackoverflow.com/questions/5345152/why-would-i-prefer-using-vector-to-deque
It is controversial if one should use deque or std::vector as the main generic container.
*/
#include "common.hpp"
int main() {
// TODO example
}

View File

@ -90,7 +90,7 @@ int def_no_argname(int, int) { return 2; }
*/
int main() {
// # overload
// # Overload
{
overload(1);
assert(callStack.back() == "overload(int)");
@ -137,6 +137,15 @@ int main() {
<http://stackoverflow.com/questions/2816293/passing-optional-parameter-by-reference-in-c>
*/
/*
# volatile overload
Functions that differ by `volatile` can be overloaded:
- http://stackoverflow.com/questions/10242578/volatile-overloading
*/
{}
}
/*

66
cpp/functional.cpp Normal file
View File

@ -0,0 +1,66 @@
/*
# functional
Convenient simple functions.
They implement `operator()`, which allows you to pass them to
other stdlib functions that take functions as arguments.
*/
#include "common.hpp"
int main() {
/*
# bind2nd
TODO Deprecated?
Tranform a function that takes two arguments into a function that takes only the first.
Useful with stdlib functions that must take functions that take a single argument,
but you want to pass an extra parameter to that function.
*/
{
/*
std::vector<int> v = {2, 0, 1};
assert(std::find_if (
v.begin(),
v.end(),
std::bind2nd([](int i, int param){return i == param + 1;}, 1)
) == v.begin());
*/
}
/*
# plus
*/
{
assert(std::plus<int>()(1, 2) == 3);
}
#if __cplusplus >= 201103L
/*
# hash
http://www.cplusplus.com/reference/functional/hash/
The stdlib furnishes overloaded hash functions for stdlib containers.
Those functions are implemented as callable classes that implement `()`.
For base types, those hashes are found under the `functional`.
For std::vectors, only `std::vector<bool>` has a template.
For other types, they are found in the same header that defines those types:
ex: hash for std::vectors is under `<vector>`.
Returns a `size_t` result.
*/
{
std::cout << "hash" << std::endl;
std::cout << " 1 = " << std::hash<int>()(1) << std::endl;
std::cout << " string abc = " << std::hash<std::string>()("abc") << std::endl;
}
#endif
}

1
cpp/interactive/Makefile Symbolic link
View File

@ -0,0 +1 @@
../Makefile

1
cpp/interactive/common.hpp Symbolic link
View File

@ -0,0 +1 @@
../common.hpp

View File

@ -0,0 +1,14 @@
/*
# sleep_for
*/
#include "common.hpp"
int main() {
int i = 0;
while (1) {
std::cout << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
i++;
}
}

361
cpp/iterator.cpp Normal file
View File

@ -0,0 +1,361 @@
/*
# iterator
Iteration could be done with random access in certain data structures with a for i loop.
Iterators are better becase you can also use them for structures without random access,
so if you decide to change structures in the future the job will be much easier.
# iterator categories
Iterators are categorized depending on the operations they can do:
<http://www.cplusplus.com/reference/iterator/>
The clases are (from least to most versatile):
- Input Output
- Forward
- Bidirectional
- Random Access
The most versatile iterators (random access) behave much like pointers,
and overload most pointer operations such as integer increment `it + 1` and
pointer dereference `*it` in a similar way to pointers.
Those classes are not language enforced via inheritance like in Java,
but could be used by programmers to implement typedefs that explain
the types of operations permitted. So if you are going to use a typedef
solution not to tie yourself to a given container, consider naming the
typdefed as one of the classes to indicate the operationt can do:
typedef random_it std::vector<int>::iterator;
It is possible to retreive the class of an interator via `std::iterator_traits<ITER>::interator_category`.
*/
#include "common.hpp"
int main() {
// Before C++11: begin and end were the only way to use iterators.
// After C++11; the range based syntax is the best way to use them.
{
/*
# forward iteration
Can be done on all containers.
# begin
Returns an iterator to the first element.
# end
Returns an iterator to the first element *after* the last.
*/
{
std::vector<int> v{1, 2, 0};
int i = 0;
int is[]{1, 2, 0};
for (auto it = v.begin(); it != v.end(); ++it) {
assert(*it == is[i]);
++i;
}
}
/*
# backwards iteration
Can only be done on biderectional containers.
# rbegin
Reversed begin.
Returns a `reverse_iterator` that points to the last emlement.
++ on reversed iterators decreases them.
# rend
Returns a reversed iterator to the element before the first.
*/
{
std::vector<int> v{1, 2, 0};
int i;
int is[]{1, 2, 0};
i = 2;
for (auto it = v.rbegin(); it != v.rend(); ++it) {
assert(*it == is[i]);
//cout << *it << endl;
--i;
}
}
}
/*
# range based for loop #foreach
C++11
Like python foreach or Java improved-for loop.
This is the best way to iterate a container with C++11.
Much easier to write or read.
Also have the advantage that you don't need to specify iterator type!
Behind the scenes, this method is still based on iterators,
and the class to be iterated needs to implement:
- begin()
- end()
And the iterator returned must implement:
- operator++()
- operator!=()
- operator*()
*/
{
#if __cplusplus >= 201103L
//forward
{
// If `int&` is used, no useless copies are made.
// and the vector can be modified directly.
{
std::vector<int> v{1, 2, 0};
int is[]{1, 2, 0};
int i = 0;
for (int& iv : v) {
assert(iv == is[i]);
//cout << iv << endl;
iv++;
i++;
}
assert((v == std::vector<int>{2, 3, 1}));
}
// Without `&`, makes copies of each element.
// Usually not what we want.
{
std::vector<int> v{1, 2, 0};
int is[]{1, 2, 0};
int i = 0;
for (int iv : v) {
assert(iv == is[i]);
//cout << iv << endl;
iv++;
i++;
}
assert((v == std::vector<int>{1, 2, 0}));
}
// Less code duplication with auto.
// This is the best way to do it.
{
std::vector<int> v{1, 2, 0};
int is[]{1, 2, 0};
int i = 0;
for (auto& iv : v) {
assert(iv == is[i]);
//cout << *it << endl;
i++;
}
}
}
/*
# range based for loop for arrays
Also works for bare arrays for which the size is known at compile time!
*/
{
{
int is[]{1, 2};
for (int& i : is) {
i *= 2;
}
assert(is[0] == 2);
assert(is[1] == 4);
}
/*
does not work for dynamic memory since
there would be no way to know the array size at compile time
*/
{
//int *is = new int[2];
//is[0] = 1;
//is[0] = 2;
//for (int &i : is) {
// i *= 2;
//}
//delete[] is;
}
}
#endif
/*
backwards
TODO possible? Seems not out of the C++11 box: <http://stackoverflow.com/questions/8542591/c11-reverse-range-based-for-loop>
Auto is a lifesaver here to avoid typing the iterator type.
*/
{
std::vector<int> v = {1, 2, 0};
int i;
int is[] = {1, 2, 0};
//forward
{
i = 2;
for (auto it = v.rbegin(); it != v.rend(); ++it) {
assert(*it == is[i]);
//cout << *it << endl;
i--;
}
}
}
}
/*
# generic containers
There is no standard iterator independent from container.
This can be done via type erasure techinques.
But would mean loss of performance because of lots of polymorphic calls
and stdlib is obssessed with performance.
The best solution seems to use typedefs:
typedef it_t std::vector<int>::iterator;
And then if ever your container changes all you have to do is modify one single typedef:
typedef it_t set<int>::iterator;
TODO isnt auto and range based for a better solution in c++11?
*/
{
std::vector<int> v{1, 2};
std::set<int> s{1, 2};
std::vector<int>::iterator itVec(v.begin());
std::set<int>::iterator itSeti(s.begin());
// Does not exist:
//iterator<int> itVec = v.begin();
//iterator<int> itSeti = s.begin();
// Best workaround is using auto:
auto vit(v.begin());
auto sit(v.begin());
}
// No born checking is done
{
std::vector<int> v{1, 2};
// Last element.
*(v.end() - 1);
// After last element no born check.
*(v.end());
// No such method.
//(v.end().hasNext());
}
/*
Base pointers and arrays can be used anywhere iterators can.
The stdlib functions have specializations for pointers.
<http://stackoverflow.com/questions/713309/c-stl-can-arrays-be-used-transparently-with-stl-functions>
*/
{
int is[]{2, 0, 1};
int j = 0;
for (auto& i : is) {
assert(i == is[j]);
j++;
}
}
/*
# size_t for slt containers
See size_type.
# size_type
Random access containers such as std::vectors, strings, etc have a `size_type` member typedef
that represents a type large enough to hold its indexes.
For arrays, this type is exactly the C `size_t`.
For a std::vector, it will also probably be `size_t`, since std::vectors are array backed,
but using `size_type` gives more generality.
This type is returned by methods such as `size()`.
*/
{
std::vector<int> v{2, 0, 1};
std::vector<int>::size_type i(1);
v[i] = 1;
}
/*
# iterator_traits
Contain information about iterators.
This allows to create template functions that take generic iterators independent of the
exact container type as is the case for many function sunder `<algorithm>`.
*/
{
//value_type
//pointer
//reference
{
typedef std::iterator_traits<std::vector<int>::iterator>::value_type ValueType;
typedef std::iterator_traits<std::vector<int>::iterator>::pointer Pointer;
typedef std::iterator_traits<std::vector<int>::iterator>::reference Reference;
assert(typeid(ValueType) == typeid(int));
assert(typeid(Pointer) == typeid(int*));
assert(typeid(Reference) == typeid(int&));
}
/*
# difference_type
The type returned on a difference between two pointers.
Unlike size_type, this value is signed, since the difference may well be negative.
*/
{
typedef typename std::iterator_traits<std::vector<int>::iterator>::difference_type DifferenceType;
std::vector<int> v{0, 1};
assert(typeid(v.end() - v.begin()) == typeid(DifferenceType));
}
/*
# iterator_category
iterator_category is a struct *type*, not a value.
Therefore, in order to compare it one must use `typeid`.
*/
{
assert(typeid(std::iterator_traits<std::vector<int>::iterator>::iterator_category)
== typeid(std::random_access_iterator_tag));
}
}
}

47
cpp/list.cpp Normal file
View File

@ -0,0 +1,47 @@
/*
# list
Doubly linked list.
Advantages over std::vector: fast inservion and removal from middle.
Unless you really need those operations fast, don't use this data structure.
No random access.
# forward_list
Like list, but singly linked, and therefore not backwards interable.
*/
#include "common.hpp"
int main() {
//initializer list constructor
{
std::list<int> l{0, 1};
}
// # emplace
{
std::list<int> l{0, 1};
l.emplace(++l.begin(), 2);
assert(l == std::list<int>({0, 2, 1}));
}
// # remove: remove all elements with a given value from list
{
std::list<int> l{0, 1, 0, 2};
l.remove(0);
assert(l == std::list<int>({1, 2}));
}
// # splice: transfer elements from one list to another
{
std::list<int> l{0, 1};
std::list<int> l2{2, 3};
l.splice(++l.begin(), l2);
assert(l == std::list<int>({0, 2, 3, 1}));
assert(l2 == std::list<int>());
}
}

File diff suppressed because it is too large Load Diff

189
cpp/map.cpp Normal file
View File

@ -0,0 +1,189 @@
/*
# map
http://www.cplusplus.com/reference/map/map/
Also comes in an unordered version `unordered_map`.
Ordered.
Also comes in an multiple value input version `multimap`.
Does not require a hash function. Usually implemented as a self balancing tree such as a rb tree.
# unordered_map
TODO complexity comparison to map.
# hashmap
There seems to be no explicit hashmap container, only a generic map interface,
See map.
Nonstandard `hash_map` already provided with gcc and msvc++.
It is placed in the `std::` namespace, but it is *not* ISO.
*/
#include "common.hpp"
template <class K, class V>
std::string map_to_str(std::map<K,V> map) {
std::stringstream result;
for (auto& pair : map) {
result << pair.first << ":" << pair.second << ", ";
}
return result.str();
}
int main() {
/*
The initializer list constructor makes things very easy.
*/
{
std::map<int,std::string> m{
{0, "zero"},
{1, "one"},
{2, "two"},
};
}
/*
emplace
put a value pair into the map without creating the pair explicitly
needs gcc 4.8: <http://stackoverflow.com/questions/15812276/stdset-has-no-member-emplace>
*/
{
//std::map<int,std::string> m;
//m.emplace(0, "zero");
//m.emplace(1, "one");
//m.emplace(2, "two");
}
/*
# insert
Insert pair into map.
The return value is similar to that of a set insertion with respec to the key.
*/
{
std::map<int,std::string> m;
std::pair<std::map<int,std::string>::iterator,bool> ret;
ret = m.insert(std::pair<int,std::string>(0, "zero"));
assert(ret.first == m.find(0));
assert(ret.second == true);
ret = m.insert(std::pair<int,std::string>(1, "one"));
assert(ret.first == m.find(1));
assert(ret.second == true);
//key already present
ret = m.insert(std::pair<int,std::string>(1, "one2"));
assert(m[1] == "one");
assert(ret.first == m.find(1));
assert(ret.second == false);
}
/*
iterate
Map is ordered.
It is iterated in key `<` order.
Iteration returns key value pairs.
*/
{
std::map<int,std::string> m{
{1, "one"},
{0, "zero"},
};
int i = 0;
int is[] = {0, 1};
for (auto& im : m) {
assert(im.first == is[i]);
//cout << im->second << endl;
++i;
}
assert(i == 2);
assert(map_to_str(m) == "0:zero, 1:one, ");
}
/*
[] operator
get value from a given key
WARNING: if the key does not exist, it is inserted with a value with default constructor.
This can be avoided by using `find` instead of `[]`.
*/
{
std::map<int,std::string> m{
{0, "zero"},
{1, "one"},
};
assert(m[0] == "zero");
assert(m[1] == "one");
//inserts `(3,"")` because `""` is the value for the default string constructor
assert(m[2] == "");
assert(m.size() == 3);
}
/*
# find #check if in map
Similar to `std::set` find with respect to the keys:
returns an iterator pointing to the pair which has given key, not the value.
If not found, returns `map::end()`
This is perferrable to `[]` since it does not insert non-existent elements.
*/
{
std::map<int,std::string> m{
{0, "zero"},
{1, "one"},
};
assert(m.find(0)->second == "zero");
assert(m.find(1)->second == "one");
assert(m.find(2) == m.end());
assert(m.size() == 2);
}
/*
erase
Remove element from map.
Returns number of elements removed.
*/
{
int ret;
std::map<int,std::string> m{
{0, "zero"},
{1, "one"},
};
std::map<int,std::string> m2;
m2.insert(std::pair<int,std::string>(0, "zero"));
ret = m.erase(1);
assert(ret = 1);
assert(m == m2);
ret = m.erase(1);
assert(ret == 0);
}
}

View File

@ -11,8 +11,6 @@
#include "common.hpp"
#if __cplusplus >= 201103L
const int NUM_THREADS = 1000;
const int NUM_ITERS = 1000;
long int global = 0;
std::mutex mutex;
@ -34,15 +32,13 @@ int main() {
#if __cplusplus >= 201103L
std::thread threads[NUM_THREADS];
int i;
for (i = 0; i < NUM_THREADS; ++i) {
for (i = 0; i < NUM_THREADS; ++i)
threads[i] = std::thread(threadMain);
}
for (i = 0; i < NUM_THREADS; ++i) {
for (i = 0; i < NUM_THREADS; ++i)
threads[i].join();
if (global != NUM_OPS) {
printf("fraction of errors = %f\n", (1.0 - (double)global/NUM_OPS));
assert(false);
}
assert(global == NUM_THREADS * NUM_ITERS);
#endif
}

View File

@ -105,15 +105,21 @@ class OperatorOverload {
/*
operator++
Post and pre increment are both impemented via this operator.
<http://stackoverflow.com/questions/6375697/overloading-pre-increment-operator>
- http://stackoverflow.com/questions/3846296/how-to-overload-the-operator-in-two-different-ways-for-postfix-a-and-prefix
- http://stackoverflow.com/questions/6375697/do-i-have-to-return-a-reference-to-the-object-when-overloading-a-pre-increment-o
- http://stackoverflow.com/questions/3574831/why-does-the-postfix-increment-operator-take-a-dummy-parameter
*/
const OperatorOverload& operator++() {
this->i++;
return *this;
}
// TODO this is wrong.
const OperatorOverload& operator++(int) {
this->i++;
return *this;
}
/*
Ambiguous call.
@ -316,17 +322,20 @@ int main() {
assert(OperatorOverload(1) + OperatorOverload(2) == OperatorOverload(3));
// ++
{
// Prefix
{
OperatorOverload i(1);
assert(++i == OperatorOverload(2));
assert(i == OperatorOverload(2));
}
/* TODO understand and get working */
/*
i = OperatorOverload(1);
assert(i++ == OperatorOverload(1));
assert(i == OperatorOverload(2));
*/
// Postfix. TODO
{
OperatorOverload i(1);
//assert(i++ == OperatorOverload(1));
//assert(i == OperatorOverload(2));
}
}
// -

View File

@ -30,8 +30,14 @@ int main() {
*/
{
#ifdef __cplusplus
printf("__cplusplus = %li\n", __cplusplus);
std::cout << "__cplusplus = " << __cplusplus << std::endl;
#endif
}
#ifdef __STDCPP_THREADS__
// TODO why not defined even though I do have multithreading?
std::cout << "__STDCPP_THREADS__" << __cplusplus << std::endl;
assert(__STDCPP_THREADS__ == 1);
#endif
}
}
}

18
cpp/regex.cpp Normal file
View File

@ -0,0 +1,18 @@
/*
# regex
Finally they are supported!
Many types are supported: Javascript, grep, awk, ...
It is probably saner and more powerful to stick to Javascript regexes.
*/
#include "common.hpp"
int main() {
#if __cplusplus >= 201103L
// Js has `[:d:]` equivalent POSIX `[:digit:]`.
std::regex r("a.(c|d)");
#endif
}

12
cpp/rtti.md Normal file
View File

@ -0,0 +1,12 @@
# RTTI
Run time type information.
Any function that gets class information explicitly at runtime:
- `typeid`
- `dynamic_cast`
Google style 3.26 discourages this, since if you really need it your design is probably flawed.
Also using `typeid` on variables means that extra meta data must be kept about those variables.

151
cpp/set.cpp Normal file
View File

@ -0,0 +1,151 @@
/*
# set
- unique elements: inserting twice does nothing
- always ordered: $O(log)$ find / insert
- immutable elements: it is not possible to modify an object,
one must first remove it and resinsert.
This is so because modification may mean reordering.
*/
#include "common.hpp"
int main() {
// C++11 initializer list
{
{
std::set<int> s{1, 2, 0, 1};
std::set<int> s2{0, 1, 2};
assert(s == s2);
}
{
std::set<std::string> s = {"a", "c", "b", "a"};
std::set<std::string> s1 = {"a","b", "c"};
assert(s == s1);
}
}
// You can modify objects if you store pointers.
{
int i = 0;
std::set<int*> s;
s.insert(&i);
std::set<int*>::iterator it = s.find(&i);
*(*it) = 1;
assert(i == 1);
}
/*
# insert
Like for std::vector, insert makes copies.
Return is a pair conatining:
- if the item was not present, an iterator to the item inserted and true
- if the item was present, an iterator to the existing item inserted and false
*/
{
std::pair<std::set<int,std::string>::iterator,bool> ret;
std::set<int> s;
ret = s.insert(1);
assert(ret.first == s.find(1));
assert(ret.second == true);
ret = s.insert(2);
assert(ret.first == s.find(2));
assert(ret.second == true);
ret = s.insert(0);
assert(ret.first == s.find(0));
assert(ret.second == true);
//item already present:
//nothing is done and returns false on the pair
ret = s.insert(1);
assert(ret.first == s.find(1));
assert(ret.second == false);
std::set<int> s1 = {0, 1, 2};
assert(s == s1);
}
/*
# erase
Remove element from set.
Returns number of elements removed.
*/
{
std::set<int> s = {0, 1, 2};
assert(s.erase(1) == 1);
std::set<int> s2 = {0, 2};
assert(s == s2);
assert(s.erase(1) == 0);
}
// ERROR no random access since it uses bidirection iterator.
{
//cout << s[0] << endl;
}
//size
{
std::set<int> s;
assert(s.size() == 0);
s.insert(0);
assert(s.size() == 1);
}
/*
iterate
Biderectional iterator.
Always sorted.
*/
/*
find
If found, returns an iterator pointing to the element.
Else, returns `map::end()`
find is `log n` time since the container is ordered.
log n time complexity since always sorted
*/
{
std::set<int> s = {0, 1, 2};
std::set<int>::iterator it;
it = s.find(1);
assert(*it == 1);
it = s.find(3);
assert(it == s.end());
}
/*
count
Count how many times an item is in the set.
Can only return 1 or 0.
Equivalent to doing a find.
*/
{
std::set<int> s = {1, 2, 0, 1};
assert(s.count(1) == 1);
assert(s.count(3) == 0);
}
}

View File

@ -18,6 +18,36 @@ Write `stdlib` and say "Standard Library" instead.
GCC comes with an implementation of libstdc++.
It is the main Linux implementation.
Shared object name: `libstdc++.so`.
Website: <http://gcc.gnu.org/libstdc++/>
Get source code: seems to be on the same tree as gcc?
git clone git://gcc.gnu.org/git/gcc.git
Find the shared library:
locate libstdc++
Common location on Linux:
/usr/lib/ARCH-linux-gnu/libstdc++.so.X
Locate the headers
locate /iostream
Common location:
/usr/include/c++/4.X/`.
The Ubuntu package is called `libstdc++6.X`. `dpkg -l | grep libstd`.
With `g++` the C++ standard library is linked against automatically. This does not happen when compiling with `gcc`, and is one of the many reasons why you should use `g++` whenever compiling C++ instead of `gcc`.
### Apache C++ Standard Library
Dead.

28
cpp/static_assert.cpp Normal file
View File

@ -0,0 +1,28 @@
/*
# static_assert
Make assertions at compile time.
In this way you don't waste time compiling large programs,
or do potentially dangerous runtime operations to test your program.
Probably became possible on C++11 because of features such as `constexpr`,
which allow to better manage compile time constantness.
<http://stackoverflow.com/questions/1647895/what-does-static-assert-do-and-what-would-you-use-it-for>
*/
#include "common.hpp"
int main() {
#if __cplusplus >= 201103L
static_assert(0 < 1, "msg");
// ERROR: static assertion failed
//static_assert(0 > 1, "msg");
std::srand(time(NULL));
// ERROR: needs to be a constexpr
//static_assert(std::rand() >= 0);
#endif
}

310
cpp/string.cpp Normal file
View File

@ -0,0 +1,310 @@
/*
# string
*/
#include "common.hpp"
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
int main() {
// Initialize from string literal.
{
std::string s = "abc";
}
// cout works as expected.
{
std::string s = "abc";
std::stringstream oss;
oss << s;
assert(oss.str() == "abc");
}
/*
# + for strings
# cat
# concatenate.
Creates a new string.
The only way to do inline this without creating a new string seems to be by using stringstream.
http://stackoverflow.com/questions/662918/how-do-i-concatenate-multiple-c-strings-on-one-line
*/
{
std::string s = "ab";
std::string s1 = "cd";
assert(s + s1 == "abcd");
assert(s + "cd" == "abcd");
assert("cd" + s == "cdab");
}
// length
{
std::string s = "abc";
assert(s.length() == 3);
}
{
std::string s = "abc";
s[0] = 'A';
assert(s == "Abc");
// BAD: no born check! Compiles.
//s[3] = 'd';
}
/*
# lowercase
http://stackoverflow.com/questions/313970/stl-string-to-lower-case
*/
{
// Best stdlib way with transform:
std::string s = "AbCd1_";
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
assert(s == "abcd1_");
//Boost has a single function: boost::algorithm::to_lower(str);
}
/*
# c_str
Convert std::string to C null terminated char* string.
*/
{
std::string s = "abc";
assert((std::strcmp(s.c_str(), "abc")) == 0);
}
// # substring
{
std::string s = "abcde";
assert(s.substr(1, 3) == "bcd");
}
// # Split at a character into array of strings.
{
// Best stdlib solution for any character: http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c
// There are shorters sstream solutions that split at whitespace.
// For Boost it's a one liner.
{
assert((split("01:23::45", ':') == std::vector<std::string>{"01", "23", "", "45"}));
std::vector<std::string> v;
split("01:23::45", ':', v);
assert((v == std::vector<std::string>{"01", "23", "", "45"}));
}
}
/*
# strip
# chomp
# trim
Exact same techniques as removing elements from vectors but for characters.
It's just that those operations are so common on strings...
http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
*/
{
// A single character: remove and erase idiom.
// Single remove_all call in Boost.
{
std::string s = "a bc d";
auto end = s.end();
s.erase(std::remove(s.begin(), end, ' '), end);
assert((s == "abcd"));
}
// Any character in a string: remove_if + custom function. std::ispunct is a typical choice.
// Single liner with boost::remove_if + is_any_of.
{
std::string s = "a,bc. d";
auto end = s.end();
// stdc ispunct:
s.erase(std::remove_if(s.begin(), end, ::ispunct), end);
// stdlib ispunct. Fails without the cast.
//s.erase(std::remove_if(s.begin(), end, (int(*)(int))std::ispunct), end);
assert((s == "abc d"));
}
}
/*
# getline
Read istream until a any given character, by default newline, and store chars read into a string.
The other major method of getting data from streams is `operator<<`,
which generaly speaking reads until whitespace. getline is generaly saner.
Returns the stream itself, which allows to:
- chain calls
- do while(getline) combos, as streams can be converted to bool via the `void*()`
operator which returns a pointer type which is then converted to a boolean.
*/
{
// Up to newline.
{
std::stringstream ss;
std::string s;
ss << "ab\n\nc";
// The delim is removed from the string.
assert(std::getline(ss, s));
assert(s == "ab");
// Empty
assert(std::getline(ss, s));
assert(s == "");
// No problem if end of stream.
assert(std::getline(ss, s));
assert(s == "c");
// Stream over.
assert(!std::getline(ss, s));
}
// The stream itself is returned.
{
std::stringstream ss;
std::string s;
std::string s2;
ss << "ab\n\nc";
std::getline(std::getline(ss, s), s2);
assert(s == "ab");
assert(s2 == "");
}
// Up to custom char.
{
std::stringstream ss;
std::string s;
ss << "ab::f";
std::getline(ss, s, ':');
assert(s == "ab");
}
// Read stream line-wise.
{
std::stringstream ss;
std::string line;
std::vector<std::string> lines;
ss << "ab\n\nc";
while (getline(ss, line))
lines.push_back(line);
assert((lines == std::vector<std::string>{"ab", "", "c"}));
}
}
/*
# stringstream
# basic_stringstream
An iostream String backed implementation.
The following is defined:
typedef basic_stringstream<char> stringstream;
typedef basic_stringstream<char>
Very useful to test streams without creating files / stdin.
*/
{
std::stringstream oss("abcd");
// str does not clear the std::stringstream object
assert(oss.str() == "abcd");
// To clear it you could do: http://stackoverflow.com/questions/20731/in-c-how-do-you-clear-a-stringstream-variable
// Set to empty:
oss.str("");
// Clear flags. Very important, not only for error indicators but also for end of stream.
oss.clear();
assert(oss.str() == "");
// ERROR: use of deleted function because the constructor is =delete.
//oss = std::stringstream();
}
// Possible application: build up a huge string step by step.
// May be more efficient than concatenations which always generates new objects.
{
std::stringstream oss;
oss << "ab";
oss << "cd";
assert(oss.str() == "abcd");
}
/*
# int to string
There are a few standard alternatives.
<http://stackoverflow.com/questions/5590381/easiest-way-to-convert-int-to-string-in-c>
*/
{
/*
C++11 solves the question once and for all with a robust one-liner for base types.
It is not intended however for class input.
*/
#if __cplusplus >= 201103L
assert(std::to_string(123) == "123");
#endif
/*
std::stringstream seems to be the best pre C++11 solution.
It also has the advantage of working for any class that implements `operator<<`.
*/
{
std::stringstream oss;
oss << 123;
assert(oss.str() == "123");
}
/*
C sprintf
Works, but uses too many conversion operations.
*/
{
char cs[16];
std::sprintf(cs, "%d", 123);
std::string s = (cs);
assert(s == "123");
}
}
// #int to string
// http://stackoverflow.com/questions/7663709/convert-string-to-int-c
{
// Best C++11 error checking option: stoi
#if __cplusplus >= 201103L
assert(std::stoi("123") == 123);
#endif
}
}

42
cpp/struct.cpp Normal file
View File

@ -0,0 +1,42 @@
/*
# struct
Structs in C++ are very similar to classes: support access modifiers,
inheritance, constructors, templates, etc.
The major difference between them is that the default access modifier for structs
is public, while for classes it is private.
This is why structs are used on many simple short language examples:
no public line is needed.
The Google C++ style guide recommends using struct only if there is no constructors,
and classes otherwise.
<http://stackoverflow.com/questions/2750270/c-c-struct-vs-class>
*/
#include "common.hpp"
template<class T>
struct BaseStruct {
T i;
BaseStruct(T i) : i(i) {}
protected:
int iProtected;
private:
int iPrivate;
};
struct DerivedStruct : BaseStruct<int> {
DerivedStruct(int i) : BaseStruct(i) {
iProtected = i;
}
};
int main() {
struct DerivedStruct s(1);
assert(s.i == 1);
}

View File

@ -1,7 +1,5 @@
/*
TODO this example is too complex, split it up into smaller examples.
# Thread
# thread
# Multithreading
@ -14,72 +12,22 @@ TODO this example is too complex, split it up into smaller examples.
#include "common.hpp"
int nNsecs = 10;
int threadGlobal = 0;
int threadGlobalMutexed = 0;
std::mutex threadGlobalMutex;
std::thread::id lastThreadId;
std::set<std::thread::id> threadIds;
int threadGlobalEq0 = 0;
int threadGlobalMutexedEq0 = 0;
int threadChange = 0;
void threadMain(int threadCountToSqrt) {
std::thread::id id = std::this_thread::get_id();
for (int i = 0; i < threadCountToSqrt; i++) {
for (int j = 0; j<threadCountToSqrt; j++) {
if (lastThreadId != id) {
++threadChange;
//threadIds.insert(id);
lastThreadId = id;
}
// cout is not thread safe order gets mixed up.
//std::cout << id << " " << i << endl;
// If happens.
threadGlobal = 1;
if (threadGlobal == 0)
++threadGlobalEq0;
threadGlobal = 0;
// If never happens!
threadGlobalMutex.lock();
// if not available, wait
//threadGlobalMutex.try_lock();
// If not available, return!
threadGlobalMutexed = 1;
if (threadGlobalMutexed == 0)
++threadGlobalMutexedEq0;
threadGlobalMutexed = 0;
threadGlobalMutex.unlock();
}
}
std::this_thread::sleep_for (std::chrono::nanoseconds(nNsecs));
// Done, pass to another thread.
std::this_thread::yield();
}
int main() {
// Start threads.
std::thread t1(threadMain, 1000);
std::thread t2(threadMain, 1000);
// Ensure that both threads ended.
t1.join();
t2.join();
assert(threadChange > 0);
//assert(threadIds.size() == 2);
//assert(threadGlobalEq0 > 0);
assert(threadGlobalMutexedEq0 == 0);
std::thread::id mainId = std::this_thread::get_id();
std::this_thread::sleep_for(std::chrono::nanoseconds(nNsecs));
std::this_thread::yield();
/* # get_id */
{
std::thread::id id = std::this_thread::get_id();
std::cout << "get_id = " << id << std::endl;
}
/*
# hardware_concurrency
Get the number of threads.
http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
*/
{
unsigned int n = std::thread::hardware_concurrency();
std::cout << "hardware_concurrency = " << n << std::endl;
}
}

69
cpp/typeid.cpp Normal file
View File

@ -0,0 +1,69 @@
/*
# typeid
Get type of variables.
Can be done for both types and variables of the type.
Returns objects of `type_info`
# type_info
Type returned by `typeid`.
*/
#include "common.hpp"
int main() {
/*
typeid returns `type_info`.
However copy and assign for type_info are private,
so the following fails.
*/
{
//std::type_info t = typeid(int);
//std::type_info t(typeid(int));
}
// type_info implements `==` and `!=`.
//
// typeid's of different types are always different.
{
int i, i1;
int& ia = i;
class Class {};
Class c;
assert(typeid(i) == typeid(int) );
assert(typeid(ia) == typeid(int&));
assert(typeid(i) == typeid(i1) );
assert(typeid(i) != typeid(c) );
}
/*
`name`: return a string representation of the type.
The exact string is implementation defined.
`name()` is implementation defined.
On GCC, you can demangle with `__cxa_demangle`:
http://stackoverflow.com/questions/4465872/why-typeid-name-returns-weird-characters-using-gcc
*/
{
std::cout << "typeid(int).name() = " << typeid(int).name() << std::endl;
}
// before: <http://stackoverflow.com/questions/8682582/what-is-type-infobefore-useful-for>
// hash_code: return a size_t hash of the type
/*
# type_index
Wrapper around type_info that allows copy and assign.
*/
{
std::type_index t = typeid(int);
}
}

177
cpp/utility.cpp Normal file
View File

@ -0,0 +1,177 @@
/*
# utility
Lots of miscelaneous utilities.
http://en.cppreference.com/w/cpp/utility
*/
#include "common.hpp"
int main() {
#if __cplusplus >= 201103L
/*
# tuple
Hold a ordered collection of elements.
Each element can be of a different type.
The length is always fixed.
*/
{
//create
{
//constructor
{
std::tuple<int,char,std::string> t0(0, 'a', "a");
}
/*
# make_tuple
forwards arguments to tuple constructor.
The advantage over the constructor is that since it is a function
template argument deduction can be done, so we don't need to type in
template arguments.
Remember that template argument deduction cannot be done for constructors.
*/
{
std::tuple<int,char,std::string> t;
//without make_tuple
t = std::make_tuple(0, 'a', "a");
t = std::tuple<int,char,std::string>(0, 'a', "a");
//with make_tuple
}
//tuple from pair
{
std::tuple<int,char> t2( std::pair<int,char>(0, 'a'));
}
//uniform initialization
{
std::tuple<int,char,std::string> t{0, 'a', "a"};
}
// Fails because the tuple constructor are is `explicit`!
// TODO Rationale? <http://stackoverflow.com/questions/14961809/returning-a-tuple-from-a-function-using-uniform-initialization-syntax>
{
//std::tuple<int, int> t = {0, 1};
//std::tuple<int, int> t[]{{0, 1}};
}
}
/*
# get
Get single element from tuple.
Returns references, so it is possible to modify the tuples with them.
Copies are made from input elements
*/
{
std::tuple<int,std::string> t0(0, "abc");
assert(std::get<0>(t0) == 0);
assert(std::get<1>(t0) == "abc");
std::get<0>(t0) = 1;
assert(std::get<0>(t0) == 1);
std::get<1>(t0)[0] = '0';
assert(std::get<1>(t0) == "0bc");
}
/*
# tie
Unpack a tuple.
Unpack by reference seems not to be possible: <http://stackoverflow.com/questions/16571883/unpacking-a-std-tuple-into-pointers>
# ignore
Magic that exists only to ignore one of tie outputs.
*/
{
int i;
std::string s;
std::tuple<int,float,std::string> t(1, 1.5, "abc");
std::tie(i, std::ignore, s) = t;
assert(i == 1);
assert(s == "abc");
// Clearly copies are made.
i = 2;
assert(std::get<0>(t) == 1);
}
/*
Relational operators operations are implemented
<http://www.cplusplus.com/reference/tuple/tuple/operators/>
`<` family is lexicographical.
*/
{
std::tuple<int,char> t0(0, 'a');
std::tuple<int,char> t1(0, 'a');
std::tuple<int,char> t2(1, 'b');
std::tuple<int,char> t3(-1, 'b');
std::tuple<int,char> t4(0, 'b');
assert(t0 == t1);
assert(t0 != t2);
assert(t0 < t2);
assert(t0 > t3); //-1 counts
assert(t0 < t4); //0 ties, 'a' < 'b'
}
//swap contents of two tuples of same type
{
std::tuple<int,char> t0(0, 'a');
std::tuple<int,char> t1(1, 'b');
std::tuple<int,char> old_t0 = t0;
std::tuple<int,char> old_t1 = t1;
t0.swap(t1);
assert(t0 == old_t1);
assert(t1 == old_t0);
}
}
#endif
/*
# pair
Particular case of tuple for two elements
Methods which also exist for tuple will not be discussed.
Specially important because of `map`.
*/
{
//access: can also be done via `.first` and `.second` in addition to tuple `get`.
{
std::pair<int,char> p(0, 'a');
assert(std::get<0>(p) == p.first);
assert(std::get<1>(p) == p.second);
}
}
/*
# forward
TODO
*/
{
}
}

61
cpp/valarray.cpp Normal file
View File

@ -0,0 +1,61 @@
/*
# valarray
Array of values. Wors much like a mathematical vector.
Container that overloads many mathematical operations in a similar way to what Fortran does,
which may be more efficient and convenient.
Very obscure, for several reasons:
- other techniques achieve what it achieves
- low compiler support
Downsides compared to vectors:
- not resizable, so no push_back
<http://stackoverflow.com/questions/1602451/c-valarray-vs-vector>
*/
#include "common.hpp"
int main() {
std::valarray<int> v;
std::valarray<int> v0{0, 1, 2};
std::valarray<int> v1{3, 4, 5};
assert(v0.sum() == 3);
assert(v0.min() == 0);
assert(v0.max() == 2);
/*
v = v0;
v.cshift(1);
assert((v == std::valarray<int>{1, 2, 0}).min());
*/
// == is elementwise equality.
//
// For equality of all elements, do `.min() == true`
{
std::valarray<int> v0{0, 1, 2};
std::valarray<int> v1{0, 2, 2};
assert(((v0 == v1) == std::valarray<bool>{true, false, true}).min());
}
// +, -, *, /, etc are overloaded elementwise.
//
// They are also overloaded for contained data type.
{
assert((v0 + v1 == std::valarray<int>{3, 5, 7}).min());
assert((v0 + 1 == std::valarray<int>{1, 2, 3}).min());
}
// Basic cmath functions are overloaded for valarray elementwise.
{
assert((abs(std::valarray<int>{-1, 0, 1}) == std::valarray<int>{1, 0, 1}).min());
assert((pow(std::valarray<int>{-2, 0, 2}, 2) == std::valarray<int>{4, 0, 4}).min());
}
}

528
cpp/vector.cpp Normal file
View File

@ -0,0 +1,528 @@
/*
# vector
Array backed conatiner that grows / shrinks as necessary.
$O(1)$ random access.
$O(n)$ element removal from interior
$O(1)$ element append to end (amortized, $O(n)$ worst case)
All methods that work for several SLT containers shall only be cheated here once.
*/
#include "common.hpp"
int main() {
// Create
{
// Empty
{
std::vector<int> v;
// C++11 initializer lists:
std::vector<int> v1{};
assert(v == v1);
}
/*
Fill constructor.
Make a `std::vector` with n copies of a single value.
*/
{
//copies of given object
{
assert(std::vector<int>(3, 2) == std::vector<int>({2, 2, 2}));
}
//default constructed objects. int = 0.
{
assert(std::vector<int>(3) == std::vector<int>({0, 0, 0}));
}
}
// Range copy.
{
std::vector<int> v{0, 1, 2};
std::vector<int> v1(v.begin(), v.end());
assert(v == v1);
}
// From existing array.
{
int myints[]{0, 1, 2};
std::vector<int> v(myints, myints + sizeof(myints) / sizeof(int));
std::vector<int> v1 = {0, 1, 2};
assert(v == v1);
}
}
// Vectors have order.
{
std::vector<int> v{0, 1, 2};
std::vector<int> v1{2, 1, 0};
assert(v != v1);
}
/*
# Contigous storage
# Data
Storage is required to be contiguous by TR1:
http://stackoverflow.com/questions/849168/are-stdvector-elements-guaranteed-to-be-contiguous
C++11 introduces the `data()` method which returns a pointer to the first element.
It works even if the vector is empty.
http://stackoverflow.com/questions/6485496/how-to-get-stdvector-pointer-to-the-raw-data
Before C++11, `&v[0]` works for non-empty vectors.
`vector<bool>` as usual is an exception.
*/
{
std::vector<int> v{0, 1, 2};
assert(&v[0] == v.data());
// True because contiguous:
assert(v.data()[1] == v[1]);
}
// size methods
{
/*
# size
# length of vector
# size_type
Number of elements in std::vector.
This has type std::vector<X>::size_type
*/
{
std::vector<int> v;
assert(v.size() == 0);
v.push_back(0);
assert(v.size() == 1);
}
/*
# resize
If larger than current size, append given element at end.
If smaller than current size, remove elements from end.
*/
{
// Reduce size
{
std::vector<int> v{0, 1};
v.resize(1);
assert((v == std::vector<int>{0}));
}
// Increase size
{
// Using default constructor objects.
{
std::vector<int> v{1};
v.resize(3);
assert((v == std::vector<int>{1, 0, 0}));
}
// Using copies of given object.
{
std::vector<int> v{1};
v.resize(3, 2);
assert((v == std::vector<int>{1, 2, 2}));
}
}
}
}
// Capacity methods.
{
/*
# capacity
Get currently allocated size.
Different from size, which is the number of elements in the std::vector!
At least as large as size.
Likely to be a power of 2 on most implementations.
*/
{
std::vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
assert(v.capacity() >= 3);
std::cout << "capacity = " << v.capacity() << std::endl;
}
// # max_size: estimative of what your OS allows you to allocate
{
std::cout << "max_size (MiB) = " << std::vector<int>().max_size() / (1 << 20) << std::endl;
}
// # reserve: increase allocated size if larger than current size.
{
std::vector<int> v;
v.reserve(3);
assert(v.capacity() >= 3);
// size() is untouched
assert(v.empty());
}
#if __cplusplus >= 201103L
// # shrink_to_fit
{
std::vector<int> v{0, 1};
v.reserve(4);
v.shrink_to_fit();
assert(v.capacity() == 2);
}
#endif
}
// `std::vector` stores copies of elements, not references.
{
std::string s = "abc";
std::vector<std::string> v{s};
v[0][0] = '0';
assert(v[0] == "0bc");
assert(s == "abc");
}
// Modify.
{
{
std::vector<int> v;
v = {0};
v = {0, 1};
assert((v == std::vector<int>{0, 1}));
}
/*
# push_back
# append
Push to the end of the std::vector.
Amortized time O(1), but may ocassionaly make the std::vector grow,
which may required a full data copy to a new location if the
current backing array cannot grow.
# push_front
Does not exist for std::vector, as it would always be too costly (requires to move
each element forward.) Use deque if you need that.
*/
{
std::vector<int> v;
std::vector<int> v1;
v.push_back(0);
v1 = {0};
assert(v == v1);
v.push_back(1);
v1 = {0, 1};
assert(v == v1);
/*
push_back makes copies with assign `=`
If you want references, use pointers, or even better, auto_ptr.
*/
{
std::vector<std::string> v;
std::string s = "abc";
v.push_back(s);
v[0][0] = '0';
assert(v[0] == "0bc");
//s was not changed
assert(s == "abc");
}
}
/*
# pop_back
Remove last element from std::vector.
No return val. Rationale: <http://stackoverflow.com/questions/12600330/pop-back-return-value>
*/
{
std::vector<int> v{0, 1};
v.pop_back();
assert(v == std::vector<int>{0});
v.pop_back();
assert(v == std::vector<int>{});
}
/*
# insert
This operation is inneficient for `std::vector` if it is not done at the end.
# concatenate
The range form of insert can be used to append one vector to anoter.
*/
{
// Single element form.
{
std::vector<int> v = {0,1};
std::vector<int> v1;
v.insert(v.begin(), -1);
v1 = {-1, 0, 1};
assert(v == v1);
v.insert(v.end(), 2);
v1 = {-1, 0, 1, 2};
assert(v == v1);
}
// Range form.
{
std::vector<int> v = {0,1};
std::vector<int> v1 = {2,3};
v.insert(v.end(), v1.begin(), v1.end());
assert((v == std::vector<int>{0, 1, 2, 3}));
}
}
/*
# erase
Remove given elements from container given iterators to those elements.
This operation is inneficient for std::vectors,
since it may mean reallocation and therefore up to $O(n)$ operations.
Returns a pointer to the new location of the element next to the last removed element.
*/
{
// Single element
{
std::vector<int> v{0, 1, 2};
auto it = v.erase(v.begin() + 1);
assert((v == std::vector<int>{0, 2}));
assert(*it == 2);
}
// Range
{
std::vector<int> v{0, 1, 2, 3};
auto it = v.erase(v.begin() + 1, v.end() - 1);
assert((v == std::vector<int>{0, 3}));
assert(*it == 3);
}
}
/*
# remove
Helper to remove all elements that compare equal to a value from container.
Does not actually remove the elements: only ensures that the beginning of the range
does not contain the item to be removed.
Ex:
0, 1, 0, 2, 0, 1
Value to remove: `0`
Range to remove from:
0, 1, 0, 2, 0, 1
----------
After the remove:
1, 2, X, Y, 0, 1
----------
where `X` and `Y` are trash, and not necessarily 0!
To actually remove the items, an `erase` is needed after remove
because `remove` is not a class method and thus cannot remove items from a container.
This is called the erase and remove idiom.
After a remove the container becomes:
1, 2, 0, 1
# erase and remove idiom
# remove and erase idiom
See remove.
*/
{
// Verbose version
{
std::vector<int> v{0, 1, 0, 2, 0, 1};
auto end = std::next(v.end(), -2);
auto firstTrashIt = std::remove(v.begin(), end, 0);
// Unpredictable result:
std::cout << "remove:";
for (auto& i : v) std::cout << " " << i;
std::cout << std::endl;
v.erase(firstTrashIt, end);
assert((v == std::vector<int>{1, 2, 0, 1}));
}
// Compact version
{
std::vector<int> v{0, 1, 0, 2, 0, 1};
auto end = std::next(v.end(), -2);
v.erase(std::remove(v.begin(), end, 0), end);
assert((v == std::vector<int>{1, 2, 0, 1}));
}
}
// # remove_if # filter
// Algorithm. Remove if a given function evaluates to true on an element.
{
std::vector<int> v{0, 1, 2, 3, 4};
auto end = v.end();
v.erase(std::remove_if(v.begin(), end, odd), end);
assert((v == std::vector<int>{0, 2, 4}));
// Common combo with lambdas
{
std::vector<int> v{0, 1, 2, 3, 4};
auto end = v.end();
v.erase(std::remove_if(v.begin(), end,
[](int i) {return i % 2 == 1;}), end);
assert((v == std::vector<int>{0, 2, 4}));
}
}
// # transform
// Algorithm. Replace elements by output of a function.
{
std::vector<int> v{0, 1, 2};
std::transform(v.begin(), v.end(), v.begin(),
[](int i) {return i * i;});
assert((v == std::vector<int>{0, 1, 4}));
}
// # clear
{
std::vector<int> v{0, 1, 2};
v.clear();
assert(v.size() == 0);
}
/*
# print vector
# vector to string
No built-in way.
http://stackoverflow.com/questions/4850473/pretty-print-c-stl-containers
190 votes on question, 30 on top answer! Come on C++!
http://stackoverflow.com/questions/1430757/c-vector-to-string?lq=1
*/
// ERROR: no default operator `<<`.
//cout << v;
}
// Random access is O(1) since array backed
{
std::vector<int> v{0, 1, 2};
// First element:
assert(v.front() == 0);
assert(v.front() == v[0]);
// Last element:
assert(v.back() == 2);
// Nth element:
v[0] = 1;
assert(v[0] == 1);
/*
BAD: just like array overflow will not change std::vector size,
and is unlikelly to give an error
*/
{
//v1[2] = 2;
}
// #back Get reference to last element in vector.
// #front Get reference to first element in vector.
// #at Like `[]`, but does bound checking and throws `out_of_range` in case of overflow.
{
std::vector<int> v{0, 1, 2};
assert(v.front() == 0);
assert(v.at(1) == 1);
assert(v.back() == 2);
try {
assert(v.at(3) == 0);
} catch (std::out_of_range& e) {
} catch (...) {
assert(false);
}
}
}
/*
# bool std::vector
*bool std::vectors are evil!*
The standard requires `vector` to have an specialization for bool which packs bits efficiently.
While efficient, in order to work this specialization breaks common std::vector interfaces
that require taking addresses only in the case of this specialization, since it does not
make sense to takes addresses anymore.
Alternatives to `vector<bool>`: <http://stackoverflow.com/questions/670308/alternative-to-vectorbool>
A good alternative seem to be deque<bool>, which behaves as intended.
*/
{
// Works fine and dandy as expected.
{
std::vector<int> v{1, 0};
int& i(v[0]);
}
// Does not compile!!!
{
std::vector<bool> v{true, false};
//bool& b(v[0]);
}
// It was not a problem with bool, the problem really is `vector<bool>`.
{
bool b[]{true, false};
bool& b2(b[0]);
}
}
}

View File

@ -1,3 +1,2 @@
# Redefine entire GCC to remove pedantic.
PEDANTIC :=
STD := gnu11

33
gcc/atomic_fetch_add.c Normal file
View File

@ -0,0 +1,33 @@
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>
enum CONSTANTS {
NUM_THREADS = 1000,
NUM_ITERS = 1000
};
int global = 0;
void* main_thread(void *arg) {
int i;
for (i = 0; i < NUM_ITERS; ++i) {
#ifdef FAIL
global++;
#else
__atomic_fetch_add(&global, 1, __ATOMIC_SEQ_CST);
#endif
}
return NULL;
}
int main() {
int i;
pthread_t threads[NUM_THREADS];
for (i = 0; i < NUM_THREADS; ++i)
pthread_create(&threads[i], NULL, main_thread, NULL);
for (i = 0; i < NUM_THREADS; ++i)
pthread_join(threads[i], NULL);
assert(global == NUM_THREADS * NUM_ITERS);
return EXIT_SUCCESS;
}

View File

@ -1,2 +0,0 @@
LIBS := -lm -pthread
D := #-DFAIL

View File

@ -1 +0,0 @@
../Makefile_params

View File

@ -58,16 +58,10 @@ void* main_thread(void *arg) {
int main() {
pthread_t threads[NUM_THREADS];
int i;
for (i = 0; i < NUM_THREADS; ++i) {
for (i = 0; i < NUM_THREADS; ++i)
pthread_create(&threads[i], NULL, main_thread, NULL);
}
for (i = 0; i < NUM_THREADS; ++i) {
for (i = 0; i < NUM_THREADS; ++i)
pthread_join(threads[i], NULL);
}
assert(global == NUM_THREADS * NUM_ITERS);
return EXIT_SUCCESS;
}