Pokazywanie postów oznaczonych etykietą lib. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą lib. Pokaż wszystkie posty

7 marca 2020

OpenCV - budowanie ze źródeł

Ostatnio musiałem skomplikować OpenCV w wersji Debug. Zresztą wersja dostępna w repozytoriach Ubuntu (19.10) to obecnie 3.2, trochę stara, w porównaniu najnowszą 4.2. Pomocny link:
A tu moje (skondensowane) kroki, żebym nie zapomniał:
# Katalog roboczy
mkdir ~/opencv_workspace
cd ~/opencv_workspace
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git

# Instalacja virualenv dla Python-a. Przyda się numpy i scipy
virtualenv -p python3 venv
source venv/bin/activate
pip install numpy
pip install scipy

# Konfiguracja za pomocą CMake. 
# Wszystko co potrzebne do budowania znajdzie się w katalogu build, 
# a zainstalowane zostanie do katalogu $VIRTUAL_ENV/local/
cd opencv
mkdir build
cmake -B build/ -D CMAKE_BUILD_TYPE=Debug \
    -D OPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules/ \
    -D CMAKE_INSTALL_PREFIX=$VIRTUAL_ENV/local/ \
    -D PYTHON_EXECUTABLE=$VIRTUAL_ENV/bin/python \
    -D PYTHON_PACKAGES_PATH=$VIRTUAL_ENV/lib/python3.7/site-packages \
    -D INSTALL_PYTHON_EXAMPLES=ON

# Kompilacja i instalacja (do katalogu $VIRTUAL_ENV/local/)
cd build
make -j4
make install
Przykładowy program
#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat grayImg = cv::imread("color.png", cv::IMREAD_GRAYSCALE);
    cv::imwrite("gray.png", grayImg);
}
Kompilacja:
cd ~/opencv_workspace
g++ -I./venv/local/include/opencv4 -L./venv/local/lib -Wl,-rpath=./venv/local/lib \
    main.cpp \
    -lopencv_core \
    -lopencv_imgcodecs \
    -lopencv_imgproc
Wynik:



12 lutego 2020

[C++17] Parallel algorithms

Biblioteka standardowa w C++17 została rozbudowana o algorytmy, których praca może zostać zrównoleglona. O sposobie wykonania decyduje ExecutionPolicy przekazane do funkcji jako argument. Programista musi zapewnić, że funkcja przekazana do "algorytmu", będzie bezpieczna - nie będzie zależności między danymi (np. modyfikowanie danych, które mogą być odczytywane przez inny równoległy wątek). Dobre wytłumaczenie różnic na stackoverflow, a tutaj małe zestawienie:
  • std::execution::seq - standardowe wykonanie sekwencyjne, bez zrównoleglenia.
  • std::execution::par - równoległe wykonanie (choć nie ma obietnicy, że tak się stanie).
  • std::execution::par_unseq - równoległe wykonanie (choć nie ma obietnicy, że tak się stanie). Wymaga silniejszych gwarancji na to że przeplatane wywołanie funkcji będzie bezpieczne także w obrębie jednego wątku. Nowe procesory oferują taką możliwość dzięki instrukcjom do wektoryzacji - SIMD (Single-Instruction, Multiple-Data) parallelism.
Przykład z funkcją std::reduce, która w działaniu przypomina std::accumulate. Zsumowanie wartości w wektorze:
#include <iostream>
#include <numeric>
#include <execution>
#include <vector>

using namespace std;

int main() {
    vector<int> vec{1, 2, 3, 4};

    int result = std::reduce(std::execution::par,
                             begin(vec),
                             end(vec));

    cout << result << endl;
}
W przypadku gcc (9.2.1 20191008) wymagane było zainstalowanie dodatkowej paczki libtbb-dev (Threading Building Blocks).
$ sudo apt-get install libtbb-dev
$ g++ -std=c++17 main.cpp -ltbb
$ ./a.out

10

25 marca 2017

[python] biblioteka curses

Zawsze chciałem się nauczyć popularnych bibliotek curses/ncurses, okazuje się, że python posiada w bibliotece standardowej pewien port tej pierwszej. Największym problemem, jaki do tej pory znalazłem jest brak obsługi unicode. Nie wiem, czy nie pożałuje w przyszłości, ale przykład będzie trochę dłuższy - błyskawica.
Podsumowanie najważniejszych funkcji:
  • initscr() - inicjalizacja curses
  • start_color() - należy wywołać zaraz po initscr(), jeżeli chcemy używać kolorów
  • use_default_colors() - mówi aplikacji, aby używała kolorów z terminala.
  • halfdelay() - ile części sekundy aplikacja będzie czekała na naciśnięcie klawisz, po wywołaniu getch()
  • noecho() - nie drukuje wciśniętych klawiszy/znaków na terminalu
  • curs_set() - wyłącza pokazywanie kursora
  • init_color() - tworzy kolor, pierwszy parametr to jego identyfikator, dalsze parametry to wartości RGB, ale podawane w zakresie od 0 do 1000 każda.
  • init_pair() - tworzy parę: identyfikator koloru znaku i koloru tła. Identyfikator -1 oznacza domyślny kolor z terminala (przeźroczysty).
  • addstr() - drukuje string pod wskazanymi współrzędnymi (y, x). Ostatnim parametrem są atrybuty jakie można nadać tekstowi (np. kolor czcionki i tła). Tekst nie zostanie od razu wyświetlony, aby tak się stało konieczne jest zawołanie funkcji refresh()
  • refresh() - odrysowuje ekran
  • clear() - czyści ekran
  • endwin() - przywraca terminal do oryginalnych ustawień
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import curses
import random
from time import sleep
import os
import subprocess
import collections


Light = collections.namedtuple('Light', ['y', 'x', 'symbol'])


class LightningIndex:
    def __init__(self, index, branch):
        self.index = index
        self.branch = branch


def createLightning():
    x = curses.COLS / 2 + random.randint(-10, 10)
    y = 0
    lightning = [Light(y, x, random.choice('/|\\'))]
    branches = []
    while y < curses.LINES - 1:
        _, _, prev_symbol = lightning[-1]
        if prev_symbol == '|':
            y += 1
            symbol = random.choice('/|\\')
        elif prev_symbol == '/':
            symbol = random.choice('/|\\_')
            if symbol == '/' or symbol == '_':
                x -= 1
            if symbol != '_':
                y += 1
        elif prev_symbol == '\\':
            symbol = random.choice('/|\\_')
            if symbol == '\\' or symbol == '_':
                x += 1
            if symbol != '_':
                y += 1
        elif prev_symbol == '_':
            if lightning[-1].x < lightning[-2].x:
                symbol = random.choice('/_')
                x -= 1
            else:
                symbol = random.choice('\\_')
                x += 1
            if symbol != '_':
                y += 1

        if random.randint(0, 30) == 1:
            branches.append(createBranch(lightning[-1], Light(y, x, symbol)))

        lightning.append(Light(y, x, symbol))

    return lightning, branches


def createBranch(prev, root):
    branch = [prev, root]
    y = root.y
    x = root.x
    for i in range(random.randint(15, 30)):
        _, _, prev_symbol = branch[-1]
        if prev_symbol == '|':
            y += 1
            symbol = random.choice('/\\')
        elif prev_symbol == '/':
            symbol = random.choice('/___')
            if symbol == '/' or symbol == '_':
                x -= 1
            if symbol != '_':
                y += 1
        elif prev_symbol == '\\':
            symbol = random.choice('\\___')
            if symbol == '\\' or symbol == '_':
                x += 1
            if symbol != '_':
                y += 1
        elif prev_symbol == '_':
            if branch[-1].x < branch[-2].x:
                symbol = random.choice('/___')
                x -= 1
            else:
                symbol = random.choice('\\___')
                x += 1
            if symbol != '_':
                y += 1

        if x < 0 or x >= curses.COLS or y < 0 or y >= curses.LINES:
            break
        branch.append(Light(y, x, symbol))

    del branch[0]
    return branch


def blink(lightning, attr1, attr2):
    for l in lightning:
        scr.addstr(l.y, l.x, l.symbol, attr1)

    sleep(0.1)
    scr.refresh()

    for l in lightning:
        scr.addstr(l.y, l.x, l.symbol, attr2)

    sleep(0.1)
    scr.refresh()


def indexer(light, branches):
    res = []
    for bs in branches:
        if light.x == bs[0].x and light.y == bs[0].y:
            res.append(LightningIndex(0, bs))

    return res


scr = curses.initscr()
curses.start_color()        # Potrzebne do definiowania kolorów
curses.use_default_colors() # Używaj kolorów terminala
curses.halfdelay(5)         # Ile częśći sekundy czekamy na klawisz, od 1 do 255
curses.noecho()             # Nie drukuje znaków na wejściu
curses.curs_set(False)      # Wyłącza pokazywanie kursora

GRAY = 2
curses.init_color(1, 600, 600, 600)     # Zdefinuj kolor pod identyfikatorem 1,
                                        # daje kolor RGB, ale wartości 0-1000
curses.init_pair(GRAY, 1, -1)           # Stwórz parę tło/czcionka. -1 przeźroczyste

WHITE = 3
curses.init_pair(WHITE, curses.COLOR_WHITE, -1)

random.seed(4876)

while True:
    ch = scr.getch()        # Oczekiwanie aż upłynie czas, lub albo zostanie
                            # naciśnięty klawisz
    scr.clear()             # Czyści ekran

    if ch == ord('q'):
        break

    lightning, branches = createLightning()
    indexed = [LightningIndex(0, lightning)]

    for l in lightning:
        indexed += indexer(l, branches)

        for i in indexed:
            if i.index >= len(i.branch):
                continue

            light = i.branch[i.index]
            scr.addstr(light.y, light.x, light.symbol, curses.color_pair(GRAY))
            i.index += 1

        sleep(0.01)
        scr.refresh()       # Odświeżanie ekranu

    blink(lightning, curses.A_BOLD | curses.color_pair(WHITE),
        curses.A_NORMAL | curses.color_pair(WHITE))
    blink(lightning, curses.A_BOLD | curses.color_pair(WHITE),
        curses.A_NORMAL | curses.color_pair(WHITE))

curses.endwin()             # Przywraca terminal do oryginalnych ustawień
Linki:

24 czerwca 2016

[python] matplotlib - rysowanie wykresów

Kolejna biblioteka, którą zacząłem się bawić, służąca do rysowania wykresów: matplotlib. Bardzo przyjema dokumentacja, z dużą liczbą przykładów. Dla testu wykreśliłem pochodną i całkę oznaczoną dla funkcji:
$$ f(x) = -2x^{3} - 4x^{2} + 8x + 1 \\
f^\prime(x) = -6x^{2} - 8x + 8 \\
F(x) = \int f(x) dx = -\frac{1}{2}x^{4} - \frac{4}{3}x^{3} + 4x^{2} + x + C \\
F(-3) - F(1) = \int_{-3}^{1} f(x) dx = \left(-\frac{1}{2}x^{4} - \frac{4}{3}x^{3} + 4x^{2} + x + C\right)\Biggr|_{-3}^{1} $$
Kod programu:
#!/usr/bin/env python
# -*- coding: utf-8 -*-


import numpy as np
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt


def main():
    red_patch = mpatches.Patch(color='red', label=r'$f(x)$ - moja funkcja')
    blue_patch = mpatches.Patch(color='blue', label=r'$f^\prime(x)$ - obliczone numerycznie')
    cyan_patch = mpatches.Patch(color='cyan', label=r'$f^\prime(x)$ - obliczone recznie')
    green_patch = mpatches.Patch(color='green', label=r"$\int_{-3}^{1}f(x)$ - obliczone numerycznie")

    plt.legend(handles=[red_patch, blue_patch, cyan_patch, green_patch], loc='lower right')

    x = np.linspace(-4, 2, 10)
    x_dense = np.linspace(-4, 2)

    y_f = func(x)
    plt.plot(x, y_f, 'red', linewidth=2)

    y_deriv = derivative(func, x)
    plt.plot(x, y_deriv, 'blue', linewidth=2)

    y_own_deriv = own_deriv_func(x_dense)
    plt.plot(x_dense, y_own_deriv, 'cyan', linewidth=1)

    summo1 = definite_integral(func, a=-3, b=1)
    summo2 = own_integral_func(a=-3, b=1)
    print 'Całka oznaczona, numerycznie: %f' % summo1
    print 'Całka oznaczona, ręcznie: %f' % summo2

    current_figure = plt.gcf()
    current_figure.savefig('rachunek_rozniczkowy.png')

    plt.show()


def func(x):
    return -2 * (x ** 3) - 4 * (x ** 2) + (8 * x) + 1


def own_deriv_func(x):
    return -6 * (x ** 2) - 8 * x + 8


def own_integral_func(a, b):
    F = lambda x: -(1/2.0) * (x ** 4) - (4/3.0) * (x ** 3) + 4 * (x ** 2) + x
    return F(b) - F(a)


def derivative(fun, x):
    h = 0.2 # dx
    return (fun(x + h) - fun(x)) / h


def definite_integral(fun, a, b):
    axes = plt.gca()
    dx = (b - a) / 20.0

    summo = 0
    x = a
    while x < b:
        axes.add_patch(mpatches.Rectangle(xy=(x, 0), width=dx, height=fun(x), facecolor='green'))
        summo += dx * fun(x)
        x += dx

    return summo


if __name__ == '__main__':
    main()
Wynik:
Całka oznaczona, numerycznie: -26.080000
Całka oznaczona, ręcznie: -25.333333

1 października 2015

kompilacja clang-a i libc++

Z kolejnymi wydaniami, pojawiają się delikatne różnice w procesie instalacji, warto więc śledzić poniższe linki.
Ściągnięcie źródeł + instalacja:
git clone http://llvm.org/git/llvm.git

cd llvm/tools
git clone http://llvm.org/git/clang.git

cd llvm/projects
git clone http://llvm.org/git/compiler-rt.git

cd llvm/projects
git clone http://llvm.org/git/libcxx.git
git clone http://llvm.org/git/libcxxabi.git

cd llvm/projects
git clone http://llvm.org/git/test-suite.git

mkdir llvm_build
mkdir llvm_root
cd llvm_build

cmake -G "Unix Makefiles" DCMAKE_INSTALL_PREFIX=/home/beru/llvm_root/ ../llvm
make -j2
make install
Kompilacja prostego Hello World. Dzięki temu zlepkowi argumentów jestem w stanie używać przekompilowanej przez siebie wersji biblioteki standardowej z przekompilowaną wersją clang-a jak i tą pochodzącą z repozytorium dystrybucji.
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/beru/llvm_root/lib/

~/llvm_root/bin/clang++ main.cpp -std=c++14 -stdlib=libc++ \
    -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc \
    -I/home/beru/llvm_root/include/c++/v1/ \
    -L/home/beru/llvm_root/lib/

2 sierpnia 2015

[python] WinAppDbg

Natchniony bardzo fajnym wykładem Wesley-a McGrew - Instrumenting Point-of-Sale Malware (DEF CON 22), przyjrzałem się bibliotece WinAppDbg.



Biblioteka daje możliwość wygodnego analizowania, debugowania i manipulowania procesami w środowisku Windows. Niestety od wersji 1.5 python 3 nie jest już oficjalnie wspierany, pozostaje więc wersja dla python-a 2. Na stronie głównej projektu, autorzy podają także pokaźny zbiór linków, do podobnych projektów. Najciekawszą rzeczą jest bardzo bogata dokumentacja.
Instalacja za pomocą pip.
pip install winappdbg
I przykładowy program, nic nadzwyczajnego, moja modyfikacja drugiego przykładu z innym/lepszym formatowaniem.
from winappdbg import System

# Create a system snaphot.
system = System()

print('PID:    Exe Name:')
print('-----------------')
for process in system:
    space = ' ' * (8 - len(str(process.get_pid())) - 1)
    print(str(process.get_pid()) + ':' + space + str(process.get_filename()))

26 lipca 2015

[python] V8 JavaScript Engine

V8 to silnik JavaScript, natomiast pyv8 jest jego wrapperem do pythona.
Niestety nie udało mi się znaleźć informacji, w jaki sposób przekompilować wersję dla python-a 3. Z tego co wyczytałem projekt opiera się na boost::python-ie, może okazać się także konieczne zainstalowanie narzędzia scons. Wrapper bazuje na rewizji r19623 i skrypt budujący cofa repozytorium do tej wersji. Jest więc starsze o około 6000 commitów o tego co jest na trunku. Mam nadzieje, że nie oznacza to, że projekt obumiera.
svn checkout http://v8.googlecode.com/svn/trunk/ v8
svn checkout http://pyv8.googlecode.com/svn/trunk/ pyv8

export V8_HOME=~/v8
cp pyv8
python setup.py build

# biblioteka zostanie zapisana w ~/.local
python setup.py install --user 
Przykład:
#! /usr/bin/env python2

import PyV8

ctxt = PyV8.JSContext()
ctxt.enter()
result = ctxt.eval('var str = "Hello world!"; \
                    str.substring(1, 5);')
print(result)
Wynik:
ello

24 lipca 2015

[python] HTTP POST requests - PycURL

Kolejne podejście do wykonania HTTP POST requesta (poprzednie opisałem tutaj). Przydatne linki:
Biblioteka znacznie bardziej popularna i posiadająca wiele portów do różnych języków, co wiąże się z tym, że łatwiej jest odnaleźć przykłady i rozwiązać potencjalne problemy. W rozdziale Quick Start, znajduje się kilka interesujących, z omówieniem ich mechanizmów. Ciekawy wydał mi się pycrul.WRITEDATA. Z tego co udało mi się rozumieć, biblioteka nie posiada bufora na odpowiedź od serwera i to zadaniem aplikacji jest ustawienie go, dzięki tej opcji.
#! /usr/bin/env python3

import pycurl
import urllib.parse
from io import BytesIO

def post3():
    buffer = BytesIO()
    c = pycurl.Curl()

    c.setopt(pycurl.URL, 'http://requestb.in/kcco1337')
    c.setopt(pycurl.WRITEDATA, buffer)

    post_data = {'login': 'user1', 'password': 'hasło 1'}
    post_fields = urllib.parse.urlencode(post_data)
    c.setopt(pycurl.POST, 1)
    c.setopt(pycurl.POSTFIELDS, post_fields)

    c.perform()
    c.close()

    print(buffer.getvalue().decode('iso-8859-1'))
Raw body:
password=has%C5%82o+1&login=user1

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:
Takie mieszanie technologi, niestety sprawia, że szukanie błędów staje się trochę denerwujące, ale już po dwóch godzinach udało mi się uzyskać działający przykład, który mniej więcej jest tym co chciałem uzyskać. Co ciekawe (jak mówi dokumentacji), kod napisany w C++, rzadko będzie wymagał zmian dostosowujących go do współpracy z Boost.Python-em, co uważam jest dużym plusem.
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.so
Po 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

17 lutego 2015

Parser na bazie własnej gramatyki - pyparsing

Czasami zachodzi potrzeba, przeanalizowania danych, na które nie ma dedykowanego parsera. Niekiedy wystarcza regexp, ale jeżeli struktury danych zaczynają być zagnieżdżone, można pokusić się o stworzenie gramatyki i skorzystanie z jakiejś biblioteki. Ponieważ dawno się już tym nie zajmowałem, nie przywiązywałem szczególnej uwagi, czy biblioteka pozwala na zapis zbliżony do notacji BNF (http://pl.wikipedia.org/wiki/Notacja_BNF).

Wybrałem pierwszą z brzegu, omówioną w wykładzie Erik Rose - "Parsing Horrible Things with Python":



Dokumentacja jest moim zdaniem kiepska (pierwszy link), ale następny link (wykład Paula McGuire) bardzo ułatwiły pracę:
Instalacja pyparsing w wersji 2.0.3.
pip install pyparsing
Przykład - wyciąganie liczby ze stringu, który może być wielokrotnie zamknięty za pomocą nawiasów < i >
import pyparsing as pp

startMark = pp.Suppress(pp.Literal('<'))
endMark = pp.Suppress(pp.Literal('>'))

greet = pp.Word(pp.alphas + ',')
value = pp.Word(pp.nums)
lastContent = greet + value

expr = pp.Forward()

content = pp.Group(expr).setResultsName('Indent') | \
          pp.Group(lastContent).setResultsName('Right Content')

expr << startMark + content + endMark

grammar = expr

data = '<<Hello, 1337>>'
res = grammar.parseString(data)
print(res)
print(type(res))
print(res[0].getName())
Wynik:
[[['Hello,', '1337']]]
<class 'pyparsing.ParseResults'>
Indent
Do budowania gramatyk, najlepiej korzystać z operatorów +, ^, |. Do dopasowania tekstu służy nam wiele obiektów (tokenów) np.
  • Word - dopasowuje tekst z dowolnego złożenia znaków
  • Literal - dopasowuje zwartość do znaków dokładnie w takiej kolejności jak zostały podane
  • Suppress - dopasowuje, ale zawartość zostanie pominięta w wyniku
Problemem może być dopasowywanie do zagnieżdżonych zawartości. Token w takim przypadku, powinien odwoływać się sam do siebie. Z pomocą przychodzi Forward(), a ostateczny opis należy wykonać za pomocą operatora << (linijka 14).
Group, pozwala na grupowanie wyników/tokenów jakie pojawią się w ostatecznym wyniku.
Słowo jeszcze o metodach, które okazały się w moim przypadku niezwykle przydane:
  • delimitedList(expression, delim=',') - dopasuje wyrażenie, rozdzielone za pomocą delimitera (domyślnie jest to przecinek)
  • Group.setResultsName() - nadaje nazwę do dopasowanego tokenu, ma niby posłużyć w celu zbudowania słownika ze sparsowanymi danymi, ale ja po prostu korzystam z getName() na wynikowych danych, gdy po nich iteruje
  • ParseResults.asList() - wynik domyślnie jest obiektem ParseResult, ale możemy skorzystać z konwersji i przekształcić go na listę

22 grudnia 2014

[python] Beautiful Soup 4

Biblioteka do wyciągania danych z HTML-a i XML-a.
Różne ścieżki instalacji:
$ sudo apt-get install python-bs4
$ sudo apt-get install python3-bs4
$ pip install beautifulsoup4
BeautifulSoup zwraca obiekt reprezentujący dokument jako zagnieżdżone obiekty (kolejne pola) - każdy odpowiada prawdziwemu tag-owi. Najczęściej używane funkcji to find() i find_all(), pozwalające filtrować interesujące nas treści, ale istnieje też możliwość edytowanie struktury dokumentu.
soup = BeautifulSoup('<html>' \
                     '<a>' \
                        '<b>info1</b>' \
                        '<b>info2</b>' \
                     '</a>' \
                     '<c>text2</c>' \
                     '</html>')
print(soup.a.b.string)

tag = soup.find('a')
print(tag)
Wynik:
info1
<a><b>info1</b><b>info2</b></a>
Istnieje też możliwość tworzenia bardziej wyrafinowanych filtrów.
def filter_c_tag(tag):
    return tag.name == 'c' and tag.has_attr('item') and tag.attrs['item'] == 'bar'

soup = BeautifulSoup('<c item="bar">text1</c>' \
                     '<c item="foo">text2</c>' \
                     '<c item="bar">text3</c>')
tags = soup.find_all(filter_c_tag)
for t in tags:
    print(t.string)
Wynik
text1
text3

1 września 2014

[python] HTTP POST requests

Zadanie: jak wykonać zapytanie POST do strony. Dla testów skorzystałem z fajnej stronki http://requestb.in/, bo nie chciało mi się stawiać własnego serwera. Trzeba sobie za jej pomocą wygenerować link, który będzie służył nam do testów.
Najpierw standardowa biblioteka urllib2. W python-ie 3, została podzielona na dwie, urllib.request oraz urllib.error. W pierwszej kolejności przerabiamy parametry, które wstawimy do zapytania za pomocą urlencode() do "url-encoded" string (spacja na %20 itp.). Następnie tworzymy zapytanie url - request.Request(). Jeżeli zostanie dostarczony parametr data (jak w tym przypadku), to zapytanie będzie typu POST.
#! /usr/bin/env python3

import urllib.parse
import urllib.request

def post1():
    url = 'http://requestb.in/kcco1337'
    post_data = urllib.parse.urlencode({'login': 'user1', 'password': 'hasło 1'})

    binary_data = post_data.encode('utf-8')
    req = urllib.request.Request(url, data=binary_data)
    u = urllib.request.urlopen(req)
    print(u.read())
Raw body odebrane przez requestb.in:
login=user1&password=has%C5%82o+1
Urllib zbiera sporo krytyki, jako nieodpowiadający naszym czasom i trudny w obsłudze (muszę się z tym troszkę zgodzić). Alternatywę, którą znalazłem jest biblioteka requests, której działania nie muszę nawet opisywać.
#! /usr/bin/env python3

import requests

def post2():
    url = 'http://requestb.in/kcco1337'
    r = requests.post(url, data={'login': 'user1', 'password': 'hasło 2'})
    print(r.status_code)
    print(r.content)
Jedyną rzeczą, której nie jestem pewny jest kodowanie, najwyraźniej jednak w tym przykładzie wszystko poszło ok. Odebrane raw body:
password=has%C5%82o+2&login=user1

23 listopada 2012

Boost.Bimap

Szybkie wprowadzanie do bimapy: http://www.boost.org/doc/libs/1_42_0/libs/bimap/doc/html/boost_bimap/one_minute_tutorial.html
Bimap-a mapuje jeden klucz na drugi. W mapach klucze muszą być niepowtarzalne, bimapach każdy występujący w nich klucz i wartość musi być niepowtarzalny (wartość też jest kluczem).
#include <iostream>
#include <boost/bimap.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>

using namespace std;

template <typename T>
void show(T m)
{
    for (typename T::iterator it = m.begin(); it != m.end(); ++it)
        cout << "BiMap[" << it->first << "] = " << it->second << endl;
}

int main()
{
    typedef boost::bimap<int, string> BMap;
    BMap bm = boost::assign::list_of<BMap::relation>(1, "aaa")
                                                    (1, "zzz")
                                                    (2, "bbb")
                                                    (3, "ccc")
                                                    (4, "aaa");

    show(bm.left);
    show(bm.right);

    return 0;
}
W przykładzie nie możemy do bimapy wprowadzić nowych kluczy bo już wcześniej zastały wstawione.
Linijka 19 - istnieje już klucz 1 (linijka 18)
Linijka 22 - istnieje już klucz "aaa" (linijka 18)
Aby wyszukać odpowiednią wartość, musimy wiedzieć co w danej chwili jest kluczem. W tym celu należy skorzystać z obiektów "left" (klucz1 -> klucz2) lub "right" (klucz2 -> klucz1).
Wyniki:
BiMap[1] = aaa
BiMap[2] = bbb
BiMap[3] = ccc
BiMap[aaa] = 1
BiMap[bbb] = 2
BiMap[ccc] = 3

31 października 2012

Vector vs. List

Na tegorocznej konferencji GovingNative 2012 Bjarne Stroustrup, przedstawił kilka ciekawostek dotyczących nowości w C++:
Jednym z punków była wyższość wektora na listą. Lista góruje nad wektorem, w takich operacjach jak wstawianie oraz usuwanie elementów, jednak proces wyszukania odpowiedniego elementu w kontenerze okazuje się być naprawdę wąskim gardłem. Wektor z kolei lepiej radzi sobie z wyszukiwaniem, gorzej natomiast z usuwaniem i wstawianiem. Dzięki współczesnym procesorem korzystającym z mechanizmu dedukcji skoku, wektor okazuje się zyskiwać ogromną przewagę. Mimo iż wykonuje znacznie więcej operacji w pamięci to będą one odbywały się w cache procesora, gdzie są naprawdę szybkie.

Opis testu.
Wygeneruj N losowych liczb i wstaw je tak by zachowana została posortowana kolejność np. 5 1 4 2:
  • 5
  • 1 5
  • 1 4 5
  • 1 2 4 5

Usuń elementy z losowej pozycji np. dla 1 2 0 0, będzie to:
  • 1 2 4 5
  • 1 4 5
  • 1 4
  • 4
Na początek kilka funkcji pomocniczych. Pierwsza łączy nasz generator z rozkładem jednorodnym
TRnd get_rnd(const int max)
{
    const int seed = 858446;
    TBaseGeneratorType generator(seed);
    boost::uniform_int<> uni_dist(0, max);
    TRnd rnd(generator, uni_dist);
    return rnd;
}
Pierwsza część testu - generyczna funkcja do wstawiania, zachowując posortowaną kolejność.
template <typename T>
void insert_sort(T& con, const int size, TRnd& rnd)
{
    for (int i = 0; i < size; ++i) {
        const int value = rnd();
        typename T::iterator it = std::find_if(con.begin(), con.end(),
                                               value < _1);
        con.insert(it, value);
    }
}
Druga część testu - usuwanie wartości z losowej pozycji.
template <typename T>
void erase_by_rand_pos(T& con, TRnd& rnd)
{
    while (not con.empty()) {
        const int pos = rnd() % con.size();
        typename T::iterator it = con.begin();
        std::advance(it, pos);
        con.erase(it);
    }
}
Ciało testu:
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>

#include <boost/lambda/lambda.hpp>
#include <boost/lexical_cast.hpp>

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

using namespace std;
using namespace boost::lambda;
using namespace boost::posix_time;

typedef boost::mt19937 TBaseGeneratorType;
typedef boost::variate_generator<TBaseGeneratorType, 
                                boost::uniform_int<> > TRnd;

int main(int argc, char **argv)
{
    if (argc < 2) {
        cout << "Missing size argument" << endl;
        return -1;
    }

    TRnd rnd = get_rnd(std::numeric_limits<int>::max());
    const int size = boost::lexical_cast<int>(argv[1]);

    const ptime time_start = microsec_clock::local_time();
    cout << "Start at: " << time_start << ", size = "<< size << endl;

//    vector<int> container;
    list<int> container;
    insert_sort(container, size, rnd);

    const ptime time_insert = microsec_clock::local_time();
    cout << "Inserted sort:       " << time_insert - time_start << endl;

    erase_by_rand_pos(container, rnd);

    const ptime time_remove = microsec_clock::local_time();
    cout << "Erase at random pos: " << time_remove - time_insert << endl;
    cout << "Whole process:       " << time_remove - time_start << endl;

    return 0;
}
Wyniki. Wszystkie testy były kompilowane za pomocą g++ (4.6.3) z flagą -O2. Bjarne musiał korzystać z bardziej wyrafinowanego algorytmu niż mój, bo w jego wersji cały proces dla 200000 elementów zajął ok. 500 sekund, w moim przypadku było to już 1116 sekund (sic!), dlatego też nie testowałem powyżej tej wartości. Nie testowałem też "preallocated list" bo nie jestem pewien co to dokładnie jest.



I jeszcze jeden wykres, przedstawiający jak czasowo wyglądały poszczególne operacje, czyli wstawianie z wyszukiwaniem i usuwanie z wyszukiwaniem. Porównując dane, widać, że w przypadku listy, najwolniejszą operacją jest usuwanie z wyszukiwaniem, w przypadku wektora wstawianie z wyszukiwaniem. Usuwanie i wstawianie na wektorze powinny być jego słabym punktem, ale okazują się, że w połączeniu z wyszukiwaniem, są znacznie szybsze od tego co oferuje lista.



29 października 2012

StrictMock i referencja w konstruktorze [TRICK]

Napotkałem ostatnio taki problem (mowa tu o testach charakteryzacyjnych).

Przykład: Chcemy przetestować metodę Filter::run(). Klasa do działania potrzebuje obiektów Inc i Show. Nie mają one czysto abstrakcyjnych interfejsów (ale zrobimy dla nich mocki). Show potrzebuje do działania referencji do Inc.

Problem pojawia się, gdy mock zrobimy StrictMock-iem i będziemy chcieli go jeszcze zainicjować. Tutaj ShowMock chcemy zainicjować IncMock (linijka 49-50).
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/ref.hpp>
#include <gmock/gmock.h>

using namespace std;
using namespace ::testing;

class Inc {
public:
    virtual int inc(int v) { return v++; }
};

class IncMock : public Inc {
public:
    MOCK_METHOD1(inc, int(int));
};

class Show {
    Inc& obj;
public:
    Show(Inc& i) : obj(i) {}
    virtual void show(int v) { cout << "Val: " << obj.inc(v) << endl; }
};

class ShowMock : public Show {
public:
    ShowMock(Inc& i) : Show(i) {}
    MOCK_METHOD1(show, void(int));
};

class Filter {
    boost::shared_ptr<Show> sw;
    boost::shared_ptr<Inc> in;
public:
    Filter(boost::shared_ptr<Show> s, 
           boost::shared_ptr<Inc> i) : sw(s), in(i) {}
    void run(int val) {
        if (val > 5)
            sw->show(val);
        in->inc(val);
    }
};

TEST(FilterTest, test) {
    boost::shared_ptr<IncMock> l_incMock(new StrictMock<IncMock>());

//  NOT WORKING
//  boost::shared_ptr<ShowMock> l_showMock(new StrictMock<ShowMock>
//                                           (*l_incMock));
//  NOT WORKING
//  boost::shared_ptr<ShowMock> l_showMock(new StrictMock<ShowMock>
//                                           (boost::cref(*l_incMock)));

    boost::shared_ptr<ShowMock> l_showMock(new StrictMock<ShowMock>
                                             (boost::ref(*l_incMock)));
    Filter l_filter(l_showMock, l_incMock);

    int l_val = 8;
    EXPECT_CALL(*l_incMock, inc(l_val)).WillOnce(Return(l_val + 1));
    EXPECT_CALL(*l_showMock, show(l_val));

    l_filter.run(l_val);
}

int main(int argc, char *argv[]) {
    ::testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}
Pierwsze rozwiązanie wypluje error przy kompilacji
In file included from /home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock.h:64:0,
                 from main.cpp:4:
/home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock-generated-nice-strict.h: In constructor ‘testing::StrictMock<M>::StrictMock(const A1&) [with A1 = IncMock, MockClass = ShowMock]’:
main.cpp:48:77:   instantiated from here
/home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock-generated-nice-strict.h:174:51: error: no matching function for call to ‘ShowMock::ShowMock(const IncMock&)’
/home/niegodziwy/Downloads/gmock-1.6.0/include/gmock/gmock-generated-nice-strict.h:174:51: note: candidates are:
main.cpp:28:5: note: ShowMock::ShowMock(Inc&)
main.cpp:28:5: note:   no known conversion for argument 1 from ‘const IncMock’ to ‘Inc&’
main.cpp:26:7: note: ShowMock::ShowMock(const ShowMock&)
main.cpp:26:7: note:   no known conversion for argument 1 from ‘const IncMock’ to ‘const ShowMock&’
Co się okazuje, StrictMock ma tylko konstruktory explicit, dlatego podziała trick z boost::ref().
template <typename A1>
explicit StrictMock(const A1& a1) : MockClass(a1) {
  ::testing::Mock::FailUninterestingCalls(
      internal::ImplicitCast_<MockClass*>(this));
}
Niestety nie wiem dlaczego nie działa boost::cref() ?!

16 października 2012

Boost.Random

Boost.Random na szybko:
* Wybieramy jeden z generatorów pseudolosowych oferowanych przez bibliotekę (linia 9).
* Inicjujemy go seed-em (linia 12).
* Wybieramy rozkład zmiennej losowej (w naszym przypadku jednorodny), wybieramy też przedział, z którego będą wybierane liczby (obustronnie domknięty od 1 do 6) (linia 13).
* Łączymy generator z rozkładem w postaci naszego obiektu (kostka) (linia 16).
#include <iostream>

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>

int main()
{
    typedef boost::mt19937 TBaseGeneratorType;

    const int seed = 1337;
    TBaseGeneratorType generator(seed);
    boost::uniform_int<> uni_dist(1, 6);

    typedef boost::variate_generator<TBaseGeneratorType, boost::uniform_int<> > TVar;
    TVar die(generator, uni_dist);

    std::cout << "Na kostce wypadło: " << die() << std::endl;

    return 0;
}
Wynik:
Na kostce wypadło: 2

15 października 2012

Benchmark framework (Boost.Chrono) - część II

Druga biblioteka, z której pomocą chciałem mierzyć czas to Boost.Chrono. Nie do końca wyczuwam różnice między nią a Boost.Data_Time. Z pewnością obie mają rzeczy, których nie posiada "konkurent". Np. Boost.Chrono pozwala na zdefiniowanie z jakiego zegara systemowego będziemy wykorzystywać informacje. Ciekawe, czy zegar, który pokazuje czas wykonania danego wątku, uwzględnia, to że proces mógł być zawieszony, albo wywłaszczony na długi czas? Hmmm, jeszcze się w to nie wgłębiałem.

Pierwsza sprawa, to paczka w Ubuntu (libboost-all-dev), która ciągle wskazuje na wersję 1.46, a tam Boost.Chrono brakuje. Musiałem, wymienić to na:
apt-get install libboost1.48-all-dev
Druga spraw, to linkowanie. Chrono, korzysta z Boost.System i obie biblioteki trzeba zlinkować z programem (tu mam wątpliwości czy istnieje wersja, której nie trzeba linkować - nie doczytałem, korzystam z tego co mam w paczkach Ubuntu).

Zmiany w CMakeList.txt dla mojego projektu
project(benchmark_container_iterator)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})

find_package(Boost COMPONENTS system chrono REQUIRED)
target_link_libraries(${PROJECT_NAME}
  ${Boost_SYSTEM_LIBRARY}
  ${Boost_CHRONO_LIBRARY}
)
Dla benchmarka chciałem użyć process_cpu_clock, ale jego precyzja była do kitu. Jednak według opisu, wydaje się tym czego szukam:
Process and thread clocks are used usually to measure the time spent by code blocks, as a basic time-spent profiling of different blocks of code (Boost.Stopwatch is a clear example of this use).
Ostatecznie padło na "steady_clock"

Zasada działania, jest podobna jak w wersji poprzedniej. To bardzo proste wykorzystanie możliwości tej biblioteki.
#include <list>
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>

#include <boost/chrono.hpp>

using namespace std;
using namespace boost::assign;

int main()
{
    using namespace boost::chrono;
    steady_clock::time_point time1 = steady_clock::now();
    cout << "Start at:              " << time1 << endl;

    const int size = 400500;
    list<int> l = list_of(1337).repeat(size, 1337);

    steady_clock::time_point time2 = steady_clock::now();
    nanoseconds td_init = duration_cast<nanoseconds>(time2 - time1);
    cout << "Memory Initialization: " << td_init << endl;

    int result = 0;
    BOOST_FOREACH(int value, l) {
        if (value > result)
            result = value;
    }

    steady_clock::time_point time3 = steady_clock::now();
    nanoseconds td_find = duration_cast<nanoseconds>(time3 - time2);
    cout << "Searching:             " << td_find << endl;

    return result;
}
Wyniki:
Start at:              14714172071593 nanoseconds since boot
Memory Initialization: 128273372 nanoseconds
Searching:             29473710 nanoseconds

14 października 2012

Benchmark framework (Boost.Date_Time)

Pisząc test porównujący czas wykonania dwóch algorytmów, natchnęło mnie by zrezygnować z wołania za pomocą metody system() polecenia wyświetlającego czas i skorzystać jakiejś biblioteki.
#include <iostream>
#include <stdlib.h>

int main()
{
    system("date +%M.%S.%N");
    return 0;
}
W boost znalazłem dwie, które nadawały by się do moich potrzeb. Niestety w żadną nie zagłębiałem się dokładnie. Pierwsza to Boost.Data_Time, druga to Boost.Chrono. Tutaj będzie tylko o pierwszej.

Biblioteka, pozwala na pobieranie czasu, obliczanie czasu trwania i przesunięć w czasie. Wszystko to dla różnych systemów kalendarzowych np. UTC, kalendarz gregoriański. Pozwala też zapisywać i odczytywać datę w różnych formatach - z tego co czytałem, bo nie miałem czasu testować.

W tym programie pobieram trzykrotnie lokalny czas (UTC) z dokładnością co do milisekund (linijki 14, 20 i 30). Następny krok to obliczenie czasu trwania (linijki 21 i 31) inicjalizowania listy, oraz jej przeszukiwania.
#include <list>
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

using namespace std;
using namespace boost::assign;

int main()
{
    using namespace boost::posix_time;
    ptime time1 = microsec_clock::local_time();
    cout << "Start at:              " << time1 << endl;

    const int size = 400500;
    list<int> l = list_of(1337).repeat(size, 1337);

    ptime time2 = microsec_clock::local_time();
    time_duration td_init = time2 - time1;
    cout << "Memory Initialization: " << td_init << endl;

    int result = 0;
    BOOST_FOREACH(int value, l) {
        if (value > result)
            result = value;
    }

    ptime time3 = microsec_clock::local_time();
    time_duration td_find = time3 - time2;
    cout << "Searching:             " << td_find << endl;

    return result;
}
Wynik
Start at:              2012-Oct-14 17:13:36.716994
Memory Initialization: 00:00:00.125376
Searching:             00:00:00.021398

12 października 2012

SetArgReferee w DoAll

Czasami kod z którym mamy do czynienia, przekazuje nam wynik swojego działa zapisując go do argumentu przekazanego przez referencję. Chciało by się żeby wyglądało to troszkę schludniej, jednakże z powodów optymalizacyjnych (C++11 wprowadza coś takiego jak move constructor), trzeba z tym żyć, no i czasami testować. Google Mock wychodzi na przeciw, dostarczając m.in. metodę SetArgReferee() (jest też wersja dla wskaźników).

Poniżej będziemy testować klasę Simple, która posiada jedną metodą do zwracania pierwszego elementu wektora - returnFirst().

Przez "dependency injection", do klasy wstrzykiwany jest obiekt, który zadziała na wektorze (obróci go) nim zostanie zwrócony ten pierwszy (czyli ostatni element). Ten obiekt sobie z-mockujemy i tutaj przyda nam się SetArgReferee.
class IVecReverse {
public:
    virtual bool myReverse(std::vector<int>& v) const = 0;
};

class VecReverse : public IVecReverse {
public:
    bool myReverse(std::vector<int>& v) const {
        if (not v.empty()) {
            std::reverse(v.begin(), v.end());
            return true;
        }
        return false;
    }
};

class Simple {
public:
    Simple(IVecReverse& vs) : VecReverse(vs) {}

    int returnFirst(std::vector<int>& v) {
        if (VecReverse.myReverse(v))
            return v[0];
        return -1;
    }
protected:
    IVecReverse& VecReverse;
};
A teraz test. A więc z-mockowana metoda myReverse(), powinna przyjąć jakiś wektor (v1), który na końcu ma być odwrócony (to będzie nasze v2). Całą tą akcję trzeba zamknąć w DoAll(). W nawiasach <> dla SetArgReferee, wskazujemy numer parametru, dla którego robimy podmianę (mamy jeden argument więc będzie zero).
#include <iostream>
#include <algorithm>
#include <vector>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/list_of.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>

using namespace boost::assign;
using namespace ::testing;

class VecReverseMock : public IVecReverse {
public:
    MOCK_CONST_METHOD1(myReverse, bool (std::vector<int>&));
};

class SimpleTest : public Test {
public:
    VecReverseMock vrMock;
};

TEST_F(SimpleTest, testReturnFirst)
{
    Simple simple(vrMock);
    std::vector<int> v1 = boost::assign::list_of(3)(2)(4);
    std::vector<int> v2 = boost::assign::list_of(4)(2)(3);

    // Return musi byc ostatnie
    EXPECT_CALL(vrMock, myReverse(v1))
            .WillOnce(DoAll(SetArgReferee<0>(v2), Return(true)));
    EXPECT_EQ(4, simple.returnFirst(v1));
}

int main(int argc, char *argv[])
{
    ::testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}
A teraz krótko o DoAll(a1, a2, ..., an) - jego zadaniem jest wykonanie wszystkich akcji od "a1" do "an", wszystkie poza "an" powinny zwracać void, "an" musi coś zwrócić bo taki będzie wynik całego DoAll (w naszym przypadku jest to Return(true)).
[----------] 1 test from SimpleTest
[ RUN      ] SimpleTest.testReturnFirst
[       OK ] SimpleTest.testReturnFirst (1 ms)
[----------] 1 test from SimpleTest (1 ms total)