Super strona ułatwiająca budowanie i debugowanie wyrażeń regularnych. Nie znam nic co można by porównać do możliwości tej aplikacją, z tak przyjaznym interfejsem.
ekstaza, geniusz, przebłysk, olśnienie, półprawdy, półśrodki, przemilczenia, zaćmienia, głupstwa, kłamstewka, oszustwa, hultajstwo, wyrachowanie, nieprawda, nieobiektywność, niepodważalna prawda, nierówność, nieomylność, słuszność, perfekcja, krnąbrność ... niegodziwość
21 lipca 2015
13 lipca 2015
Boost.Python - Pisanie rozszerzeń dla python-a w C++
Boost.Python pozwala na wykorzystanie klas i metod zaimplementowanych w C++ w Pythonie i odwrotnie. Skupiłem się na pierwszej części. Garść przydatnych linków:
W pierwszej kolejności należy stworzyć plik źródłowy (tutaj SimplePrinter.cpp), z deklaracją wrappera - gdzie mówimy jakie interfejsy będą widoczny w Pythonie. Boost.Python posiada abstrakcję na std::vector, z której tutaj skorzystałem. Później korzystając z takiego modułu, należy stworzyć specjalny obiekt, dzięki któremu można skonwertować np. listę pythonową i skorzystać z danych w niej zawartych w kodzie C++ (przykład na końcu). Kilka ważnych uwag.
Na sam koniec test działania.
- http://www.boost.org/doc/libs/1_58_0/libs/python/doc/tutorial/doc/html/index.html
- https://en.wikibooks.org/wiki/Python_Programming/Extending_with_C%2B%2B
- http://stackoverflow.com/questions/6157409/stdvector-to-boostpythonlist
- https://docs.python.org/2/distutils/apiref.html#distutils.core.Extension
W pierwszej kolejności należy stworzyć plik źródłowy (tutaj SimplePrinter.cpp), z deklaracją wrappera - gdzie mówimy jakie interfejsy będą widoczny w Pythonie. Boost.Python posiada abstrakcję na std::vector, z której tutaj skorzystałem. Później korzystając z takiego modułu, należy stworzyć specjalny obiekt, dzięki któremu można skonwertować np. listę pythonową i skorzystać z danych w niej zawartych w kodzie C++ (przykład na końcu). Kilka ważnych uwag.
- Należy pamiętać aby nazwa modułu (w BOOST_PYTHON_MODULE) była identyczna z nazwą pliku biblioteki dynamicznej, inaczej podczas importowanie takiego modułu można natknąć się niewiele mówiący błąd.
- Nazywanie metody "print" sprawiła, że uzyskiwałem błąd, gdy próbowałem z takiej metody skorzystać. Najpewniej jest to związane z jakimś konfliktem, gdyż print (Python 2) jest słowem kluczowym.
#include <iostream>
#include <string>
#include <vector>
struct SimplePrinter
{
void setWords(std::vector<std::string> words) {
_words = words;
}
size_t count() const {
return _words.size();
}
void show() {
std::cout << "All: ";
for (const auto& w : _words) {
std::cout << w << " ";
}
std::cout << std::endl;
}
private:
std::vector<std::string> _words;
};
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(simple_printer)
{
class_<std::vector<std::string>>("VectorOfStrings")
.def(vector_indexing_suite<std::vector<std::string>>());
class_<SimplePrinter>("SimplePrinter")
.def("setWords", &SimplePrinter::setWords)
.def("count", &SimplePrinter::count)
.def("show", &SimplePrinter::show);
}
W celu skompilowania przykładu skorzystałem z Pythonowego distutils, które umożliwia budowanie modułów (nie miałem z tym narzędziem wcześniej do czynienia, ale wydaje się bardzo schludnym rozwiązaniem). W pierwszej kolejności należy stworzyć plik setup.py (w moim przypadku w tym samym katalogu, gdzie znajdowały się źródła). Tutaj ponownie, trzeba sprawdzić, czy nazwa modułu zgadza się z tą, która została zadeklarowana w wraperze C++. Co ważne, moja klasa korzysta z nowego standardu C++14, stąd dodatkowa flaga: extra_compile_args.#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension
setup(name="PackageName",
ext_modules=[
Extension(name="simple_printer",
sources=["SimplePrinter.cpp"],
libraries=["boost_python"],
extra_compile_args=["-std=c++14"])
])
Budowanie:$ cd cpp_boost_python $ ls setup.py SimplePrinter.cpp $ python setup.py build running build running build_ext building 'simple_printer' extension creating build creating build/temp.linux-x86_64-2.7 x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c SimplePrinter.cpp -o build/temp.linux-x86_64-2.7/SimplePrinter.o -std=c++14 cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++ creating build/lib.linux-x86_64-2.7 c++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wl,-Bsymbolic-functions -Wl,-z,relro -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security build/temp.linux-x86_64-2.7/SimplePrinter.o -lboost_python -o build/lib.linux-x86_64-2.7/simple_printer.soPo zbudowaniu biblioteka będzie znajdować się w podkatalogu build (build/lib.linux-x86_64-2.7/simple_printer.so).
Na sam koniec test działania.
$ cd build/lib.linux-x86_64-2.7 $ ls simple_printer.so $ python >>> import simple_printer >>> s = simple_printer.SimplePrinter() >>> words = simple_printer.VectorOfStrings() >>> words.extend(w for w in ["first", "second"]) >>> s.setWords(words) >>> s.count() 2 >>> s.show() All: first second
30 maja 2015
[C++11] Przekazywanie zmiennych do wątku
Najpierw kilka przydatnych metod i obiektów do eksperymentowania z std::thread i std::this_thread.
Konstruktor std::thread ma podobną konstrukcję do std::bind. Trzeba pamiętać, że domyślnie wszystkie przekazane zmienne są kopiowane. Gdy interesuje nas aby wątek wyliczył i zapisał jakąś wartość do zmiennej przekazanej przez referencję, należy skorzystać z std::ref (tak jak w przypadku std::bind).
- hardware_concurrency - informuje ile wątków ze wsparciem sprzętowym jest dostępnych w systemie. Jeżeli planujemy zrównoleglić naszą pracę, trzeba pamiętać, że jeden wątek jest już zajęty przez nasz program.
- get_id - metoda wołana z std::this_thread albo na obiekcie wątku. Pozwala zorientować się z jakim wątkiem mamy do czynienia. Standard nie definiuje co to będzie, ale gwarantuje, że taki obiekt (std::thread::id), może być porównywany i wyświetlany na standardowym wyjściu.
- sleep_for - pozwala uśpić wątek na pewien czas.
Konstruktor std::thread ma podobną konstrukcję do std::bind. Trzeba pamiętać, że domyślnie wszystkie przekazane zmienne są kopiowane. Gdy interesuje nas aby wątek wyliczył i zapisał jakąś wartość do zmiennej przekazanej przez referencję, należy skorzystać z std::ref (tak jak w przypadku std::bind).
#include <iostream>
#include <thread>
using namespace std;
struct Presenter {
void operator()(int& value) {
cout << "Slave id: " << std::this_thread::get_id() << endl;
value += 100;
std::this_thread::sleep_for(std::chrono::seconds(2));
}
};
int main() {
cout << "Possible threads: " << std::thread::hardware_concurrency() << endl;
cout << "Master id: " << std::this_thread::get_id() << endl;
int value = 1;
std::thread t{ Presenter(), std::ref(value) };
cout << "Child id from master: " << t.get_id() << endl;
t.join();
return 0;
}
Wynik:Possible threads: 4 Master id: 140557572298560 Child id from master: 140557555422976 Slave id: 140557555422976Kłopotliwe mogą okazać się wszelkie niejawne rzutowania. W przykładzie poniżej, funkcja fun() przyjmuje jako argument std::string. Wykonanie programu będzie przebiegało w ten sposób. W pierwszej kolejności do wątku przekazany zostanie wskaźnik (char const*), a następnie wykonana zostanie konwersja do std::string (już w kontekście nowego wątku). Istnieje bardzo duża szansa, że gdy konwersja się zadzieje, zmienna z głównego wątku nie będzie już istnieć, a działanie programu będzie trudne do przewidzenia. Rozwiązaniem jest wykonanie jawnego rzutowania przed przekazaniem zmiennych do std::thread.
#include <iostream>
#include <string>
#include <thread>
using namespace std;
void fun(std::string s) {
cout << "Received: " << s << endl;
}
int main() {
char buf[10];
for (int i = 0 ; i < 3; i++) {
std::sprintf(buf, "%d", i);
cout << "Setting: " << buf << endl;
std::thread t{ fun, buf };
// std::thread t{ fun, std::string(buf) }; // OK!
t.detach();
}
std::sprintf(buf, "%d", 77);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
Wynik. Jeden z wątków dokonuje konwersji z char* na std::string, gdy wątek główny zmienił już zawartość bufora na 77 (linijka 22).Setting: 0 Setting: 1 Received: 1 Received: 2 Setting: 2 Received: 77
23 maja 2015
19 maja 2015
[C++] Aggregate, trivial classes, standard-layout
Nowy standard wprowadza kilka definicji, które trzeba przyswoić.
Agregaty (tablice lub klasy), które mogą być inicjalizowane nawiasami klamrowymi (nie ma to nic wspólnego z std::initializer_list).
Jeżeli elementów, które podamy w klamrach będzie mniej, niż tych zadeklarowanych, to dla brakujących elementów zostanie (o ile to możliwe) zawołany konstruktor domyślny.
Agragaty, nie mogą mieć:
Klasy trywialne wspierają statyczną inicjalizację typu. Klasa trywialna to klasa, która ma trywialny konstruktor domyślny i jest trywialnie kopiowalna.
Klasa trywialnie kopiowalna (trivially copyable), to taka, której instancje mogą być kopiowane bitowo np. przy pomocy std::memcpy().
W opisie metod traitsów, są szczegółowe wymagania:
Typy standard-layout mają takie same ułożenie pól w pamięci jak struktury w języku C. Warunki, które muszą spełniać
Typy POD, są kompatybilne bitowo ze strukturami języka C. W nowej wersji standardu wprowadzono nową (uszczegółowioną) definicję typów POD (plain old data). Typem POD jest klasa, która jest jednocześnie trivial classes i standard-layout i jest to właściwość spełniona (rekursywnie) dla wszystkich jej pól.
W C++20 std::is_pod zostało usunięte.
Aggregate
Agregaty (tablice lub klasy), które mogą być inicjalizowane nawiasami klamrowymi (nie ma to nic wspólnego z std::initializer_list).
Jeżeli elementów, które podamy w klamrach będzie mniej, niż tych zadeklarowanych, to dla brakujących elementów zostanie (o ile to możliwe) zawołany konstruktor domyślny.
Agragaty, nie mogą mieć:
- konstruktora stworzonego przez użytkownika (ale user-declared jest w porządku)
- niestatycznych składowych zainicjowanych w miejscu deklaracji
- prywatnych lub chronionych niestatycznych pól składowych
- klas bazowych
- metod wirtualnych
#include <iostream>
#include <string>
#include <vector>
struct AggregateClass {
// AggregateClass() {} // ERROR - stworzone przez użytkownika
AggregateClass() = default; // OK - "user-declared"
int a;
std::string b;
std::vector<double> c;
};
int main() {
AggregateClass ag = {3, "text", {1.41, 3.14}};
}
Trivial classes
Klasy trywialne wspierają statyczną inicjalizację typu. Klasa trywialna to klasa, która ma trywialny konstruktor domyślny i jest trywialnie kopiowalna.
Klasa trywialnie kopiowalna (trivially copyable), to taka, której instancje mogą być kopiowane bitowo np. przy pomocy std::memcpy().
W opisie metod traitsów, są szczegółowe wymagania:
- http://en.cppreference.com/w/cpp/types/is_trivial
- http://en.cppreference.com/w/cpp/types/is_trivially_copyable
#include <iostream>
#include <type_traits>
struct Trivial {
Trivial() = default;
int value;
};
int main() {
std::cout << std::boolalpha;
std::cout << std::is_trivial<Trivial>::value << "\n";
std::cout << std::is_trivially_copyable<Trivial>::value << "\n";
std::cout << std::is_trivially_default_constructible<Trivial>::value << "\n";
}
Wynik:true true true
Standard-layout
Typy standard-layout mają takie same ułożenie pól w pamięci jak struktury w języku C. Warunki, które muszą spełniać
POD - przestarzałe od C++20
Typy POD, są kompatybilne bitowo ze strukturami języka C. W nowej wersji standardu wprowadzono nową (uszczegółowioną) definicję typów POD (plain old data). Typem POD jest klasa, która jest jednocześnie trivial classes i standard-layout i jest to właściwość spełniona (rekursywnie) dla wszystkich jej pól.
W C++20 std::is_pod zostało usunięte.
- https://stackoverflow.com/questions/48225673/why-is-stdis-pod-deprecated-in-c20
- http://en.cppreference.com/w/cpp/types/is_pod
Przykład dla POD i standard-layout
#include <iostream>
#include <type_traits>
struct A {
int field;
};
struct B {
int field1;
private:
int field2;
};
int main()
{
std::cout << std::boolalpha;
std::cout << "A trivial: " << std::is_trivial<A>::value << "\n";
std::cout << "A standard_layout: " << std::is_standard_layout<A>::value << "\n";
std::cout << "A pod: " <<std::is_pod<A>::value << "\n";
std::cout << "\n";
std::cout << "B trivial: " << std::is_trivial<B>::value << "\n";
std::cout << "B standard_layout: " << std::is_standard_layout<B>::value << "\n";
std::cout << "B pod: " << std::is_pod<B>::value << "\n";
}
Wynik:A trivial: true A standard_layout: true A pod: true B trivial: true B standard_layout: false B pod: false
14 maja 2015
[C++] std::thread is low level primitive
Na obiektach std::thread zawsze należy wołać join() lub detach(), a brak decyzji skutkuje poważnym błędem. Operacje tworzenia obiektu i "decyzja" o jego losie są rozłączne, co niechybnie zachęca do popełniania pomyłek. Większość książkowych przykładów zachęca do pisania własnych wraperów typu RAII, ale dlaczego sam standard nie oferuje czegoś podobnego? Odpowiedź przyniósł bardzo fajny wpis na blogu Andrzeja Krzemieńskigo.
std::thread należy rozpatrywać jako nisko poziomowy (low level) prymityw. std::thread jest tylko budulcem do tworzenia wysoko pozimowych rozwiązań, tak jak delete, jest budulcem, dzięki któremu może istnieć std::unique_ptr. W momencie wprowadzania tego rozwiązania komitetowi standaryzacyjnemu po prostu zabrakło czasu, na coś więcej. Tak jak należy wystrzegać się delete, w produkcyjnym kodzie, tak samo powinno być traktowane std::thread. Być może boost::strict_scoped_thread będzie dobrym rozwiązaniem.
std::thread należy rozpatrywać jako nisko poziomowy (low level) prymityw. std::thread jest tylko budulcem do tworzenia wysoko pozimowych rozwiązań, tak jak delete, jest budulcem, dzięki któremu może istnieć std::unique_ptr. W momencie wprowadzania tego rozwiązania komitetowi standaryzacyjnemu po prostu zabrakło czasu, na coś więcej. Tak jak należy wystrzegać się delete, w produkcyjnym kodzie, tak samo powinno być traktowane std::thread. Być może boost::strict_scoped_thread będzie dobrym rozwiązaniem.
#include <iostream>
#include <thread>
#include <boost/thread/scoped_thread.hpp>
void f()
{
std::cout << "Hello" << std::endl;
}
int main()
{
std::thread t1(f);
t1.join();
boost::strict_scoped_thread<> t2((boost::thread(f))); // podwójne nawiasy
return 0;
}
I jeszcze konfiguracja CMakeLists.txtproject(cpp_thread)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
find_package(Boost COMPONENTS system thread REQUIRED)
target_link_libraries(${PROJECT_NAME}
pthread
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
)
4 maja 2015
Vim - ściąga
Robię wszystko, aby nie musieć korzystać z narzędzia jakim jest vim, ale często jest to jedyna alternatywa, do wystukiwania echo na konsoli. Kilka linków do opisów, ułatwiających pracę z tym narzędziem.
Subskrybuj:
Posty (Atom)