Ниже приведены способы подсчета битов в беззнаковом целом числе. Все эти способы помещены в пространстве имен utils. По быстроте данные способы располагаются в следующем порядке (по возрастанию):
utils::count_bits < utils::count_bits2 < utils::count_bits3 <= utils::count_bits4
В следующей ссылке предлагается более подробное описание данной темы - "Обстоятельно о подсчете единичных битов".
Всем удачи!
#include <iostream>
#include <bitset>
/* support bits count */
class Bits_Counter {
static unsigned char byte_bit_count[256]; /* lookup table */
public:
// must be called before the first call
// to the count method
void initialize() {
int cnt, n;
for (int i = 0; i < 256; i++) {
cnt = 0;
n = i;
while (n != 0) {
n = n & (n - 1);
cnt++;
}
byte_bit_count[i] = cnt;
}
}
int count(unsigned int n) {
const unsigned char * byte = (unsigned char *) &n;
return byte_bit_count[byte[0]] + byte_bit_count[byte[1]] +
byte_bit_count[byte[2]] + byte_bit_count[byte[3]];
}
};
unsigned char Bits_Counter::byte_bit_count[256];
/* utilities for count bits in given number */
namespace utils {
using namespace std;
// show bits
void show_bits(unsigned int n) {
string binary;
while (n != 0) {
binary = bitset<8>(n).to_string();
cout << binary << endl;
n = n >> 1;
}
}
// count bits
int count_bits(unsigned int n) {
int cnt = 0;
while (n != 0) {
if (n & 1) cnt++;
n = n >> 1;
}
return cnt;
}
// count bits
int count_bits2(unsigned int n) {
int cnt = 0;
while (n != 0) {
n = n & (n - 1);
cnt++;
}
return cnt;
}
// count bits
int count_bits3(unsigned int n) {
Bits_Counter bits_counter;
bits_counter.initialize();
return bits_counter.count(n);
}
// count bits
int count_bits4(unsigned int n) {
static unsigned int mask[] = { 0x55555555,
0x33333333,
0x0F0F0F0F,
0x00FF00FF,
0x0000FFFF };
for (int i = 0, shift = 1; i < 5; i++, shift *= 2) {
n = (n & mask[i]) + ((n >> shift) & mask[i]);
}
return n;
}
};
int main()
{
unsigned int n = 55689; // 1010111000001
std::cout << utils::count_bits(n) << std::endl // 8
<< utils::count_bits2(n) << std::endl // 8
<< utils::count_bits3(n) << std::endl // 8
<< utils::count_bits4(n); // 8
return 0;
}
Oracle. Compile all of the invalid objects in your schema
For compile all of the invalid objects owned by YOUR_SCHEMA (note: must use upper case on the schema name):
begin
dbms_utility.compile_schema('YOUR_SCHEMA');
end;
If some objects are still invalid that means there is some error with them.
begin
dbms_utility.compile_schema('YOUR_SCHEMA');
end;
If some objects are still invalid that means there is some error with them.
Oracle. ANSI join syntax limitation in materialized views.
Начиная с версии 9 в Oracle для объединений таблиц стал доступен ANSI sql-синтаксиc (стандарт SQL:1999):
INNER JOIN
NATURAL JOIN
CROSS JOIN
LEFT OUTER JOIN
RIGHT OUTER JOIN
FULL OUTER JOIN
Данный синтаксис для современного разработчика более естественен, по сравнению с "old-style". Так же данный синтаксис расширяет возможности объединения таблиц (например, возможность полного объединения с использованием FULL OUTER JOIN). Но тем не менее получается, что полностью от старого синтаксиса невозможно отказаться, если Вам необходимо использовать в своих решениях материализованные представления (MATERIALIZED VIEWS) в режиме ON COMMIT. Связано это с тем, что при создании представления невозможно использовать объединения "ANSI-style".
Напоследок напомню про один нюанс использования объединений старого стиля: использовать метку (+) необходимо непосредственно с полем объединения, например:
select t1.*, t2.*
from table1 t1, table2 t2
/* where regexp_substr(t1.field, '\d+') = regexp_substr(t2.field, '\d+') (+) */
where regexp_substr(t1.field, '\d+') = regexp_substr(t2.field (+), '\d+')
В примере ошибочный вариант использования (+) закомментирован.
Или такой пример:
select t1.*, t2.*
from table1 t1, table2 t2
where t1.id = t2.id (+)
and regexp_like(t2.field (+), '^[A-Za-z]+')
Всем удачи :)
INNER JOIN
NATURAL JOIN
CROSS JOIN
LEFT OUTER JOIN
RIGHT OUTER JOIN
FULL OUTER JOIN
Данный синтаксис для современного разработчика более естественен, по сравнению с "old-style". Так же данный синтаксис расширяет возможности объединения таблиц (например, возможность полного объединения с использованием FULL OUTER JOIN). Но тем не менее получается, что полностью от старого синтаксиса невозможно отказаться, если Вам необходимо использовать в своих решениях материализованные представления (MATERIALIZED VIEWS) в режиме ON COMMIT. Связано это с тем, что при создании представления невозможно использовать объединения "ANSI-style".
Напоследок напомню про один нюанс использования объединений старого стиля: использовать метку (+) необходимо непосредственно с полем объединения, например:
select t1.*, t2.*
from table1 t1, table2 t2
/* where regexp_substr(t1.field, '\d+') = regexp_substr(t2.field, '\d+') (+) */
where regexp_substr(t1.field, '\d+') = regexp_substr(t2.field (+), '\d+')
В примере ошибочный вариант использования (+) закомментирован.
Или такой пример:
select t1.*, t2.*
from table1 t1, table2 t2
where t1.id = t2.id (+)
and regexp_like(t2.field (+), '^[A-Za-z]+')
Всем удачи :)
C++11. Recursion in lambda expression
Ниже представлен пример использования рекурсии с использованием лямбда-выражения
#include <iostream>
#include <functional>
// recursive print function
std::function<void (const std::string&, int)> print = [&] (const std::string& str, int times) {
std::cout << str;
if (times > 1) print(str, times - 1);
};
int main() {
print("!", 5); // !!!!!
return 0;
}
В данном примере в лямбда-выражении в списке захвата задан неявный захват по ссылке без которого Вы получите ошибку времени компиляции. Если Вам необходимо ограничить область захвата, тогда можно уточнить сие в списке захвата:
std::function<void (const std::string&, int)> print = [&print] (const std::string& str, int times) {
std::cout << str << std::endl;
if (times > 1) print(str, times - 1);
};
Где этим можно воспользоваться, ведь намного эффективней явно определить такого рода рекурсивную функцию:
void print(const std::string& str, int n = 1) {
std::cout << str;
if (n > 1) print(str, n - 1);
};
Все конечно зависит от задачи и Вашей фантазии. Ниже приведен один пример, где использован данный подход для сохранения общего интерфейса функций сортировки:
#include <iostream>
#include <vector>
#include <functional>
namespace util {
using namespace std;
void selection_sort(vector<int>& vec, int len);
void insertion_sort(vector<int>& vec, int len);
void bubble_sort(vector<int>& vec, int len);
void quick_sort(vector<int>& vec, int len) {
std::function<void (vector<int>&, int, int)> sorter = [&] (vector<int>& vec, int l, int r) {
int x = vec[l + (r - l) / 2];
int i = l;
int j = r;
while(i <= j) {
while(vec[i] < x) i++;
while(vec[j] > x) j--;
if (i <= j) {
swap(vec[i], vec[j]);
i++;
j--;
}
}
if (i < r) sorter(vec, i, r);
if (l < j) sorter(vec, l, j);
};
sorter(vec, 0, len - 1);
}
}
int main() {
std::vector<int> numbers = {10, 1, 9, 2, 8, 3, 7, 4, 6, 5};
util::quick_sort(numbers, numbers.size()); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
return 0;
}
#include <iostream>
#include <functional>
// recursive print function
std::function<void (const std::string&, int)> print = [&] (const std::string& str, int times) {
std::cout << str;
if (times > 1) print(str, times - 1);
};
int main() {
print("!", 5); // !!!!!
return 0;
}
В данном примере в лямбда-выражении в списке захвата задан неявный захват по ссылке без которого Вы получите ошибку времени компиляции. Если Вам необходимо ограничить область захвата, тогда можно уточнить сие в списке захвата:
std::function<void (const std::string&, int)> print = [&print] (const std::string& str, int times) {
std::cout << str << std::endl;
if (times > 1) print(str, times - 1);
};
Где этим можно воспользоваться, ведь намного эффективней явно определить такого рода рекурсивную функцию:
void print(const std::string& str, int n = 1) {
std::cout << str;
if (n > 1) print(str, n - 1);
};
Все конечно зависит от задачи и Вашей фантазии. Ниже приведен один пример, где использован данный подход для сохранения общего интерфейса функций сортировки:
#include <iostream>
#include <vector>
#include <functional>
namespace util {
using namespace std;
void selection_sort(vector<int>& vec, int len);
void insertion_sort(vector<int>& vec, int len);
void bubble_sort(vector<int>& vec, int len);
void quick_sort(vector<int>& vec, int len) {
std::function<void (vector<int>&, int, int)> sorter = [&] (vector<int>& vec, int l, int r) {
int x = vec[l + (r - l) / 2];
int i = l;
int j = r;
while(i <= j) {
while(vec[i] < x) i++;
while(vec[j] > x) j--;
if (i <= j) {
swap(vec[i], vec[j]);
i++;
j--;
}
}
if (i < r) sorter(vec, i, r);
if (l < j) sorter(vec, l, j);
};
sorter(vec, 0, len - 1);
}
}
int main() {
std::vector<int> numbers = {10, 1, 9, 2, 8, 3, 7, 4, 6, 5};
util::quick_sort(numbers, numbers.size()); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
return 0;
}
PLSQL. Bitwise operations
В plsql отсутствует нативная поддержка побитовых операций, кроме одной - bitand. При необходимости данную возможность можно реализовать самостоятельно. Ниже приведен пример реализации побитового OR и побитового XOR:
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
Для реализации операций побитовых сдвигов можно воспользоваться следующим подходом:
declare
-- convert binary to decimal
function bin2dec(binval in varchar2) return number
is
l_digits number;
l_curr_digit char(1);
l_curr_digit_dec number;
l_result number := 0;
begin
l_digits := length(binval);
for i in 1..l_digits loop
l_curr_digit := substr(binval, i, 1);
l_curr_digit_dec := to_number(l_curr_digit);
l_result := (l_result * 2) + l_curr_digit_dec;
end loop;
return l_result;
end;
-- convert decimal to binary
function dec2bin(p_num number) return varchar2
is
binval varchar2(64);
l_num number := p_num;
begin
while (l_num > 0) loop
binval := mod(l_num, 2) || binval;
l_num := trunc(l_num / 2);
end loop;
return binval;
end;
-- bitwise >> for binary
function bin_shift_right(p_bin in varchar2, p_shift in number default null) return varchar2
is
l_length number;
l_shift number;
begin
l_length := length(p_bin);
l_shift := nvl(p_shift, 1);
if (l_length <= 0) then
return null;
end if;
if (l_shift > l_length) then
l_shift := l_length;
end if;
return lpad(substr(p_bin, 1, l_length - l_shift), l_length, '0');
end;
-- bitwise >> for decimal
function shift_right(p_num in number, p_shift in number default null) return number
is
begin
if (trunc(p_num) <> p_num or p_num < 0) then
raise program_error;
end if;
return nvl(bin2dec(bin_shift_right(dec2bin(p_num), p_shift)), 0);
end;
begin
dbms_output.put_line(bin2dec('1000')); -- 8
dbms_output.put_line(shift_right(8, 1)); -- 4
dbms_output.put_line(dec2bin(shift_right(8, 1))); -- 100
end;
Ниже приведен пример использования побитовых операций для контроля возникающих в приложении ошибок:
declare
-- errors bit
ERROR_FIRST constant integer := 1; -- 0001
ERROR_SECOND constant integer := 2; -- 0010
ERROR_THIRD constant integer := 4; -- 0100
ERROR_FOURTH constant integer := 8; -- 1000
-- for capturing errors
l_errors number := 0;
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
-- set error bit
procedure set_error(p_errors in out number, p_error number)
is
begin
p_errors := bitor(p_errors, p_error);
end;
-- check if given error captured
function check_error(p_errors in number, p_error number) return boolean
is
begin
return bitand(p_errors, p_error) = p_error;
end;
-- print all captured errors
procedure print_errors(p_errors in number)
is
l_err varchar2(4000) := 'Catched errors:';
begin
if (check_error(p_errors, ERROR_FIRST)) then
l_err := l_err || ' ERROR_FIRST,';
end if;
if (check_error(p_errors, ERROR_SECOND)) then
l_err := l_err || ' ERROR_SECOND,';
end if;
if (check_error(p_errors, ERROR_THIRD)) then
l_err := l_err || ' ERROR_THIRD,';
end if;
if (check_error(p_errors, ERROR_FOURTH)) then
l_err := l_err || ' ERROR_FOURTH,';
end if;
dbms_output.put_line(l_err);
end;
begin
set_error(l_errors, ERROR_FIRST);
set_error(l_errors, ERROR_FOURTH);
print_errors(l_errors);
end;
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
Для реализации операций побитовых сдвигов можно воспользоваться следующим подходом:
declare
-- convert binary to decimal
function bin2dec(binval in varchar2) return number
is
l_digits number;
l_curr_digit char(1);
l_curr_digit_dec number;
l_result number := 0;
begin
l_digits := length(binval);
for i in 1..l_digits loop
l_curr_digit := substr(binval, i, 1);
l_curr_digit_dec := to_number(l_curr_digit);
l_result := (l_result * 2) + l_curr_digit_dec;
end loop;
return l_result;
end;
-- convert decimal to binary
function dec2bin(p_num number) return varchar2
is
binval varchar2(64);
l_num number := p_num;
begin
while (l_num > 0) loop
binval := mod(l_num, 2) || binval;
l_num := trunc(l_num / 2);
end loop;
return binval;
end;
-- bitwise >> for binary
function bin_shift_right(p_bin in varchar2, p_shift in number default null) return varchar2
is
l_length number;
l_shift number;
begin
l_length := length(p_bin);
l_shift := nvl(p_shift, 1);
if (l_length <= 0) then
return null;
end if;
if (l_shift > l_length) then
l_shift := l_length;
end if;
return lpad(substr(p_bin, 1, l_length - l_shift), l_length, '0');
end;
-- bitwise >> for decimal
function shift_right(p_num in number, p_shift in number default null) return number
is
begin
if (trunc(p_num) <> p_num or p_num < 0) then
raise program_error;
end if;
return nvl(bin2dec(bin_shift_right(dec2bin(p_num), p_shift)), 0);
end;
begin
dbms_output.put_line(bin2dec('1000')); -- 8
dbms_output.put_line(shift_right(8, 1)); -- 4
dbms_output.put_line(dec2bin(shift_right(8, 1))); -- 100
end;
Ниже приведен пример использования побитовых операций для контроля возникающих в приложении ошибок:
declare
-- errors bit
ERROR_FIRST constant integer := 1; -- 0001
ERROR_SECOND constant integer := 2; -- 0010
ERROR_THIRD constant integer := 4; -- 0100
ERROR_FOURTH constant integer := 8; -- 1000
-- for capturing errors
l_errors number := 0;
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
-- set error bit
procedure set_error(p_errors in out number, p_error number)
is
begin
p_errors := bitor(p_errors, p_error);
end;
-- check if given error captured
function check_error(p_errors in number, p_error number) return boolean
is
begin
return bitand(p_errors, p_error) = p_error;
end;
-- print all captured errors
procedure print_errors(p_errors in number)
is
l_err varchar2(4000) := 'Catched errors:';
begin
if (check_error(p_errors, ERROR_FIRST)) then
l_err := l_err || ' ERROR_FIRST,';
end if;
if (check_error(p_errors, ERROR_SECOND)) then
l_err := l_err || ' ERROR_SECOND,';
end if;
if (check_error(p_errors, ERROR_THIRD)) then
l_err := l_err || ' ERROR_THIRD,';
end if;
if (check_error(p_errors, ERROR_FOURTH)) then
l_err := l_err || ' ERROR_FOURTH,';
end if;
dbms_output.put_line(l_err);
end;
begin
set_error(l_errors, ERROR_FIRST);
set_error(l_errors, ERROR_FOURTH);
print_errors(l_errors);
end;
C++. Empty base optimization (EBO, ECBO)
Рассмотрим элиминацию (оптимизацию) пустого базового класса на примере двух классов Foo и Bar:
class Foo {};
class Bar {
Foo f;
int i;
};
Класс Foo является пустым. Как известно, размер любого объекта пустого класса как - минимум - равен 1 байту (для большинства компиляторов):
sizeof(Foo) == 1
Это достигается молчаливой вставкой компилятором одного байта (char) в такой пустой объект. Теперь посмотрим на размер класса Bar:
sizeof(Bar) == 2 * sizeof(int)
В данном случае объект класса Foo занимает 1 байт с выравниванием до размера члена i sizeof(int). Это связано с тем, что два базовых подобъекта одного типа должны иметь разные адреса.
Теперь организуем класс Bar с помощью наследования следующим образом:
class Bar : public Foo {
int i;
};
И снова посмотрим на размер класса Bar:
sizeof(Bar) == sizeof(int)
В итоге мы видим, что компилятор при таком раскладе под подобъект Foo выделил 0 байт. В этом и состоит идея оптимизации пустого базового класса. В стандарте по этому поводу сказано:
Что мы и видим на деле. Всем успехов.
class Foo {};
class Bar {
Foo f;
int i;
};
Класс Foo является пустым. Как известно, размер любого объекта пустого класса как - минимум - равен 1 байту (для большинства компиляторов):
sizeof(Foo) == 1
Это достигается молчаливой вставкой компилятором одного байта (char) в такой пустой объект. Теперь посмотрим на размер класса Bar:
sizeof(Bar) == 2 * sizeof(int)
В данном случае объект класса Foo занимает 1 байт с выравниванием до размера члена i sizeof(int). Это связано с тем, что два базовых подобъекта одного типа должны иметь разные адреса.
Теперь организуем класс Bar с помощью наследования следующим образом:
class Bar : public Foo {
int i;
};
И снова посмотрим на размер класса Bar:
sizeof(Bar) == sizeof(int)
В итоге мы видим, что компилятор при таком раскладе под подобъект Foo выделил 0 байт. В этом и состоит идея оптимизации пустого базового класса. В стандарте по этому поводу сказано:
A class with an empty sequence of [data] members and base class objects is an empty class. Complete objects and member subobjects of an empty class type shall have nonzero size.
Что мы и видим на деле. Всем успехов.
C++. Override and overload
Ниже рассмотрены случаи перекрытия (override) и перегрузки (overload) на примере двух классов Account и Deposit:
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
};
В данном случае одноименный метод display в производном классе Deposit
перекрывает (override) методы базового класса Account, таким образом
методы базового и производного классов не образуют множество перегруженных
функций.
Использование в производном классе объявления using вводит именованный
член базового класса в область видимости производного, тем самым перегружая (overload)
одноименный метод display позволяя создать единое множество перегруженных функций базового и производного классов.
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
using Account::display;
};
В виде примечания в Java понятие перекрытия существует только если у одноименных методов идентичны их сигнатуры, в остальном все методы перегружаются создавая единое множество перегруженных методов базового и производного классов:
class Account {
public void display(char fmt) {
// ...
}
public void display(int mode) {
// ...
}
}
class Deposit extends Account {
public void display(String fmt) {
// ...
}
// ...
}
Также стоит упомянуть о новом синтаксисе C++11 - использование спецификатора override. Использование данного спецификатора гарантирует, что функция 1) - является виртуальной и 2) перекрывает виртуальную функцию базового класса с идентичной ей сигнатурой:
class Alpha {
public:
virtual void foo();
void bar();
};
class Beta : public Alpha {
public:
void foo() override; // допустимо
// void foo() const override; // недопустимо
// void bar() override; // недопустимо
};
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
};
В данном случае одноименный метод display в производном классе Deposit
перекрывает (override) методы базового класса Account, таким образом
методы базового и производного классов не образуют множество перегруженных
функций.
Использование в производном классе объявления using вводит именованный
член базового класса в область видимости производного, тем самым перегружая (overload)
одноименный метод display позволяя создать единое множество перегруженных функций базового и производного классов.
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
using Account::display;
};
В виде примечания в Java понятие перекрытия существует только если у одноименных методов идентичны их сигнатуры, в остальном все методы перегружаются создавая единое множество перегруженных методов базового и производного классов:
class Account {
public void display(char fmt) {
// ...
}
public void display(int mode) {
// ...
}
}
class Deposit extends Account {
public void display(String fmt) {
// ...
}
// ...
}
Также стоит упомянуть о новом синтаксисе C++11 - использование спецификатора override. Использование данного спецификатора гарантирует, что функция 1) - является виртуальной и 2) перекрывает виртуальную функцию базового класса с идентичной ей сигнатурой:
class Alpha {
public:
virtual void foo();
void bar();
};
class Beta : public Alpha {
public:
void foo() override; // допустимо
// void foo() const override; // недопустимо
// void bar() override; // недопустимо
};
C++. Qt. Forward declaration. One way to get access to the parent form from a child form
При работе с Qt встала задача: как правильно организовать доступ к данным родительской формы из дочерней формы. Был выбран вариант передачи указателя на экземпляр данной формы в конструктор дочерней формы. В этом случае у Вас может возникнуть следующая проблема. Для родительской формы вы подключаете заголовочный файл определения класса дочерней формы. Но и дочернему классу нужно сообщить о классе (типе) родительской формы. Если подключить заголовочный файл определения класса родительской формы, то возникнет ситуация циклического подключения этих заголовочных файлов. Чтобы этого избежать, необходимо воспользоваться техникой "опережающего определения" (forward declaration):
bar.h
#include "foo.h"
class bar {
public:
bar();
};
bar.cpp
bar::bar() {
foo f ();
// work with object f
}
foo.h
class bar; // forward declaration
class foo {
public:
foo(bar* obj); // pointer or a reference
};
foo.cpp
#include "bar.h"
#include "foo.h"
foo::foo(bar* obj) {
// work with pointer obj
}
Ниже приведен пример данного подхода, в котором дочерняя форма при отрисовке таблицы со списком элементов обращается к соответствующему списку родительской формы.
item.h
#ifndef ITEM
#define ITEM
#include <QString>
class Item {
private:
int id;
QString description;
public:
Item(int id, QString description) : id(id), description(description) {}
void setId(int id) {
this->id = id;
}
int getId() const {
return id;
}
void setDescription(QString description) {
this->description = description;
}
QString getDescription() const {
return description;
}
};
#endif
mainwindow.h
#ifndef MAINWINDOW
#define MAINWINDOW
#include <QMainWindow>
#include "itemswindow.h"
#include "item.h"
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget* wgt = 0);
QList<Item> itemList;
public slots:
void slotItems();
};
#endif
mainwindow.cpp
#include <QtWidgets>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget* wgt) : QMainWindow(wgt) {
QMenu* menu = new QMenu("Menu");
menu->addAction("Exit", qApp, SLOT(quit()));
menuBar()->addMenu(menu);
// central widget
QWidget* centralWidget = new QWidget;
QVBoxLayout* buttonsWidgetLayout = new QVBoxLayout(centralWidget);
buttonsWidgetLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
QPushButton* itemsBttn = new QPushButton("Items");
itemsBttn->setFixedWidth(150);
buttonsWidgetLayout->addWidget(itemsBttn);
connect(itemsBttn, SIGNAL(clicked()), SLOT(slotItems()));
setCentralWidget(centralWidget);
setWindowTitle("MainWindow");
// for testing
itemList.append(Item(1, "First item"));
itemList.append(Item(2, "Second item"));
itemList.append(Item(3, "Third item"));
itemList.append(Item(4, "Fourth item"));
itemList.append(Item(5, "Fifth item"));
}
void MainWindow::slotItems() {
ItemsWindow* itemsWindow = new ItemsWindow(this, this);
itemsWindow->exec();
delete itemsWindow;
}
itemswindow.h
#ifndef ITEMSWINDOW
#define ITEMSWINDOW
#include <QtWidgets>
#include <item.h>
class MainWindow;
class ItemsWindow : public QDialog {
Q_OBJECT
private:
QTableWidget* table;
public:
ItemsWindow(MainWindow* mw = 0, QWidget* wgt = 0);
};
#endif
itemswindow.cpp
#include "mainwindow.h"
#include "itemswindow.h"
ItemsWindow::ItemsWindow(MainWindow* mw, QWidget* wgt) :
QDialog(wgt, Qt::WindowTitleHint | Qt::WindowCloseButtonHint) {
QVBoxLayout* verticalLayout = new QVBoxLayout;
QHBoxLayout* horizontalBottomLayout = new QHBoxLayout;
QPushButton* okBttn = new QPushButton("&OK");
okBttn->setFixedWidth(60);
connect(okBttn, SIGNAL(clicked()), SLOT(accept()));
horizontalBottomLayout->setAlignment(Qt::AlignRight);
horizontalBottomLayout->addWidget(okBttn);
table = new QTableWidget();
table->setColumnCount(2);
QStringList list;
list << "Id" << "Description";
table->setHorizontalHeaderLabels(list);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
if (mw != NULL && !mw->itemList.empty()) {
int itemsCnt = mw->itemList.count();
table->setRowCount(itemsCnt);
QTableWidgetItem* tableItem = 0;
for (int i = 0; i < itemsCnt; i++) {
Item item = mw->itemList.at(i);
tableItem = new QTableWidgetItem(QString::number(item.getId()));
tableItem->setTextAlignment(Qt::AlignCenter);
table->setItem(i, 0, tableItem);
tableItem = new QTableWidgetItem(item.getDescription());
table->setItem(i, 1, tableItem);
}
}
this->setWindowTitle("Items");
verticalLayout->addWidget(table);
verticalLayout->addLayout(horizontalBottomLayout);
setLayout(verticalLayout);
}
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char** argv) {
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
Исходники доступны по данной ссылке - source.
bar.h
#include "foo.h"
class bar {
public:
bar();
};
bar.cpp
bar::bar() {
foo f ();
// work with object f
}
foo.h
class bar; // forward declaration
class foo {
public:
foo(bar* obj); // pointer or a reference
};
foo.cpp
#include "bar.h"
#include "foo.h"
foo::foo(bar* obj) {
// work with pointer obj
}
Ниже приведен пример данного подхода, в котором дочерняя форма при отрисовке таблицы со списком элементов обращается к соответствующему списку родительской формы.
item.h
#ifndef ITEM
#define ITEM
#include <QString>
class Item {
private:
int id;
QString description;
public:
Item(int id, QString description) : id(id), description(description) {}
void setId(int id) {
this->id = id;
}
int getId() const {
return id;
}
void setDescription(QString description) {
this->description = description;
}
QString getDescription() const {
return description;
}
};
#endif
mainwindow.h
#ifndef MAINWINDOW
#define MAINWINDOW
#include <QMainWindow>
#include "itemswindow.h"
#include "item.h"
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget* wgt = 0);
QList<Item> itemList;
public slots:
void slotItems();
};
#endif
mainwindow.cpp
#include <QtWidgets>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget* wgt) : QMainWindow(wgt) {
QMenu* menu = new QMenu("Menu");
menu->addAction("Exit", qApp, SLOT(quit()));
menuBar()->addMenu(menu);
// central widget
QWidget* centralWidget = new QWidget;
QVBoxLayout* buttonsWidgetLayout = new QVBoxLayout(centralWidget);
buttonsWidgetLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
QPushButton* itemsBttn = new QPushButton("Items");
itemsBttn->setFixedWidth(150);
buttonsWidgetLayout->addWidget(itemsBttn);
connect(itemsBttn, SIGNAL(clicked()), SLOT(slotItems()));
setCentralWidget(centralWidget);
setWindowTitle("MainWindow");
// for testing
itemList.append(Item(1, "First item"));
itemList.append(Item(2, "Second item"));
itemList.append(Item(3, "Third item"));
itemList.append(Item(4, "Fourth item"));
itemList.append(Item(5, "Fifth item"));
}
void MainWindow::slotItems() {
ItemsWindow* itemsWindow = new ItemsWindow(this, this);
itemsWindow->exec();
delete itemsWindow;
}
itemswindow.h
#ifndef ITEMSWINDOW
#define ITEMSWINDOW
#include <QtWidgets>
#include <item.h>
class MainWindow;
class ItemsWindow : public QDialog {
Q_OBJECT
private:
QTableWidget* table;
public:
ItemsWindow(MainWindow* mw = 0, QWidget* wgt = 0);
};
#endif
itemswindow.cpp
#include "mainwindow.h"
#include "itemswindow.h"
ItemsWindow::ItemsWindow(MainWindow* mw, QWidget* wgt) :
QDialog(wgt, Qt::WindowTitleHint | Qt::WindowCloseButtonHint) {
QVBoxLayout* verticalLayout = new QVBoxLayout;
QHBoxLayout* horizontalBottomLayout = new QHBoxLayout;
QPushButton* okBttn = new QPushButton("&OK");
okBttn->setFixedWidth(60);
connect(okBttn, SIGNAL(clicked()), SLOT(accept()));
horizontalBottomLayout->setAlignment(Qt::AlignRight);
horizontalBottomLayout->addWidget(okBttn);
table = new QTableWidget();
table->setColumnCount(2);
QStringList list;
list << "Id" << "Description";
table->setHorizontalHeaderLabels(list);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
if (mw != NULL && !mw->itemList.empty()) {
int itemsCnt = mw->itemList.count();
table->setRowCount(itemsCnt);
QTableWidgetItem* tableItem = 0;
for (int i = 0; i < itemsCnt; i++) {
Item item = mw->itemList.at(i);
tableItem = new QTableWidgetItem(QString::number(item.getId()));
tableItem->setTextAlignment(Qt::AlignCenter);
table->setItem(i, 0, tableItem);
tableItem = new QTableWidgetItem(item.getDescription());
table->setItem(i, 1, tableItem);
}
}
this->setWindowTitle("Items");
verticalLayout->addWidget(table);
verticalLayout->addLayout(horizontalBottomLayout);
setLayout(verticalLayout);
}
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char** argv) {
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
Исходники доступны по данной ссылке - source.
C++. Qt5.6. Combobox with checkboxes
На днях работал с замечательной библиотекой Qt. Нужно было добавить возможность выбора элементов по флажкам в выпадающем списке. Вроде тривиальная gui задача, но у меня немного вызвало затруднение. Ниже приведено мое решение. Исходная платформа - Win64.
multilist.h
main.cpp
multilist.h
#ifndef MULTILIST
#define MULTILIST
#include <QtWidgets>
class MultiList : public QComboBox {
Q_OBJECT
private:
QString displayText;
QStandardItemModel *model;
public:
MultiList(QWidget *parent = 0) : QComboBox(parent) {
setEditable(true);
displayText = "";
model = new QStandardItemModel;
slotUpdateText();
connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotUpdate()));
}
void addItem(const QString &text) {
int row = model->rowCount();
QStandardItem* item = new QStandardItem();
item->setText(text);
item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
item->setData(Qt::Unchecked, Qt::CheckStateRole);
model->setItem(row, 0, item);
this->setModel(model);
}
void addItems(const QStringList &texts) {
for (int i = 0; i < texts.count(); i++) {
addItem(texts.at(i));
}
}
QStringList getCheckedItems() const {
QStringList checkedItems;
for (int i = 0; i < model->rowCount(); i++) {
if (model->item(i, 0)->checkState() == Qt::Checked) {
checkedItems << model->item(i, 0)->text();
}
}
return checkedItems;
}
void setCheckedItems(const QStringList &items) {
for (int i = 0; i < items.count(); i++) {
int index = findText(items.at(i));
if (index != -1) {
model->item(index)->setData(Qt::Checked, Qt::CheckStateRole);
}
}
slotUpdate();
}
public slots:
void slotUpdateText() {
lineEdit()->setText(displayText);
}
void slotUpdate() {
displayText = "";
for (int i = 0; i < model->rowCount(); i++) {
if (model->item(i, 0)->checkState() == Qt::Checked) {
displayText = displayText + model->item(i, 0)->text() + "; ";
}
}
QTimer::singleShot(0, this, SLOT(slotUpdateText()));
}
};
#endif
main.cpp
#include "multilist.h"
int main(int argc, char** argv) {
QApplication app(argc, argv);
MultiList *multiList = new MultiList();
multiList->addItems(QStringList() << "One" << "Two" << "Three" << "Four");
multiList->setCheckedItems(QStringList() << "One" << "Two");
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(new QLabel("Select items:"));
layout->addWidget(multiList, 1);
QWidget widget;
widget.setWindowTitle("MultiList example");
widget.setLayout(layout);
widget.show();
return app.exec();
}
PLSQL. UTL_HTTP package. Sending cyrillic chars
Если Вы используете встроенный пакет utl_http, то возможно Вы сталкивались с проблемой кодировок при отправке текстовых данных на кириллице. Для решения данной проблемы необходимо воспользоваться методов escape встроенного пакета utl_url:
utl_url.escape('Привет, мир!', true, 'utf-8')
Данный метод возвращает строку, готовую к отправке. Ниже приведен пример:
declare
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://some_address:port?test=1';
l_data varchar2(100);
begin
l_data := 'Привет, мир!';
l_data := utl_url.escape(l_data, true, 'utf-8');
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url, 'POST', 'HTTP/1.1');
/* if need proxy connection
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
utl_http.set_header(req, 'Content-Length', length(l_data));
utl_http.set_header(req, 'Content-Encoding', 'UTF-8');
-- send post data
utl_http.write_text(req, l_data);
res := utl_http.get_response(req);
utl_http.end_response(res);
/* if need check status code
res.status_code
*/
exception
when utl_http.end_of_body then
utl_http.end_response(res);
when others then
dbms_output.put_line(sqlerrm);
end;
utl_url.escape('Привет, мир!', true, 'utf-8')
Данный метод возвращает строку, готовую к отправке. Ниже приведен пример:
declare
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://some_address:port?test=1';
l_data varchar2(100);
begin
l_data := 'Привет, мир!';
l_data := utl_url.escape(l_data, true, 'utf-8');
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url, 'POST', 'HTTP/1.1');
/* if need proxy connection
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
utl_http.set_header(req, 'Content-Length', length(l_data));
utl_http.set_header(req, 'Content-Encoding', 'UTF-8');
-- send post data
utl_http.write_text(req, l_data);
res := utl_http.get_response(req);
utl_http.end_response(res);
/* if need check status code
res.status_code
*/
exception
when utl_http.end_of_body then
utl_http.end_response(res);
when others then
dbms_output.put_line(sqlerrm);
end;
PLSQL. UTL_HTTP package
Ниже приведены примеры использования встроенного пакета utl_http. Например, если Вам необходимо запросить некоторые данные по веб адресу, тогда можно воспользоваться пакетом utl_http следующим образом:
declare
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://aviationweather.gov/adds/tafs/';
param varchar2(200) := '?station_ids=vhhh' || '&' || 'std_trans=standart' || '&' || 'submit_both=Get+TAFs+and+METARs';
l_data varchar2(32000);
begin
dbms_output.enable(1000000000);
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url || param); -- GET
/* if need proxy
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'User-Agent', 'Mozilla/4.0');
res := utl_http.get_response(req);
loop
utl_http.read_line(res, l_data, true);
dbms_output.put_line(l_data);
end loop;
utl_http.end_response(res);
exception
when utl_http.end_of_body then
utl_http.end_response(res);
when others then
dbms_output.put_line(sqlerrm);
end;
В данном случае в запросе используется GET метод, если Вам необходимо использовать POST запросы, тогда можно использовать данный пакет следующим образом:
declare
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://some_address:port?test=1';
l_data varchar2(32767);
begin
l_data := 'bla-bla-bla';
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url, 'POST', 'HTTP/1.1');
/* if need proxy connection
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
utl_http.set_header(req, 'Content-Length', length(l_data));
utl_http.set_header(req, 'Content-Encoding', 'UTF-8');
-- send post data
utl_http.write_text(req, l_data);
res := utl_http.get_response(req);
utl_http.end_response(res);
/* if need check status code
res.status_code
*/
exception
when utl_http.end_of_body then
utl_http.end_response(res);
when others then
dbms_output.put_line(sqlerrm);
end;
Ниже приведен еще один пример POST запроса, но в примере рассмотрена возможность возврата полученного ответа в виде данных типа CLOB:
create or replace package body test_pkg is
procedure send_message(p_message in varchar2,
p_status out integer,
p_response out clob)
is
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://some_address:port?test=1';
buffer varchar2(4000);
clob_buffer clob;
begin
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url, 'POST', ' HTTP/1.1');
/* if need proxy connection
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
utl_http.set_header(req, 'Content-Length', length(p_message));
utl_http.set_header(req, 'Content-Encoding', 'UTF-8');
-- send post data
utl_http.write_text(req, p_message);
res := utl_http.get_response(req);
-- set response status
if res.status_code = 200 then
p_status := 1;
else
p_status := 0;
end if;
-- read response
begin
clob_buffer := empty_clob;
loop
utl_http.read_text(res, buffer, length(buffer));
clob_buffer := clob_buffer || buffer;
end loop;
p_response := clob_buffer;
utl_http.end_response(res);
exception
when utl_http.end_of_body then
p_response := clob_buffer;
utl_http.end_response(res);
when others then null;
dbms_output.put_line(sqlerrm);
dbms_output.put_line(dbms_utility.format_error_backtrace);
utl_http.end_response(res);
end;
exception
when others then
dbms_output.put_line(sqlerrm);
end;
begin
-- init
null;
end test_pkg;
declare
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://aviationweather.gov/adds/tafs/';
param varchar2(200) := '?station_ids=vhhh' || '&' || 'std_trans=standart' || '&' || 'submit_both=Get+TAFs+and+METARs';
l_data varchar2(32000);
begin
dbms_output.enable(1000000000);
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url || param); -- GET
/* if need proxy
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'User-Agent', 'Mozilla/4.0');
res := utl_http.get_response(req);
loop
utl_http.read_line(res, l_data, true);
dbms_output.put_line(l_data);
end loop;
utl_http.end_response(res);
exception
when utl_http.end_of_body then
utl_http.end_response(res);
when others then
dbms_output.put_line(sqlerrm);
end;
В данном случае в запросе используется GET метод, если Вам необходимо использовать POST запросы, тогда можно использовать данный пакет следующим образом:
declare
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://some_address:port?test=1';
l_data varchar2(32767);
begin
l_data := 'bla-bla-bla';
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url, 'POST', 'HTTP/1.1');
/* if need proxy connection
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
utl_http.set_header(req, 'Content-Length', length(l_data));
utl_http.set_header(req, 'Content-Encoding', 'UTF-8');
-- send post data
utl_http.write_text(req, l_data);
res := utl_http.get_response(req);
utl_http.end_response(res);
/* if need check status code
res.status_code
*/
exception
when utl_http.end_of_body then
utl_http.end_response(res);
when others then
dbms_output.put_line(sqlerrm);
end;
Ниже приведен еще один пример POST запроса, но в примере рассмотрена возможность возврата полученного ответа в виде данных типа CLOB:
create or replace package body test_pkg is
procedure send_message(p_message in varchar2,
p_status out integer,
p_response out clob)
is
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://some_address:port?test=1';
buffer varchar2(4000);
clob_buffer clob;
begin
utl_http.set_response_error_check(false);
req := utl_http.begin_request(url, 'POST', ' HTTP/1.1');
/* if need proxy connection
utl_http.set_proxy('company.proxy.com:port', '');
utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
*/
utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
utl_http.set_header(req, 'Content-Length', length(p_message));
utl_http.set_header(req, 'Content-Encoding', 'UTF-8');
-- send post data
utl_http.write_text(req, p_message);
res := utl_http.get_response(req);
-- set response status
if res.status_code = 200 then
p_status := 1;
else
p_status := 0;
end if;
-- read response
begin
clob_buffer := empty_clob;
loop
utl_http.read_text(res, buffer, length(buffer));
clob_buffer := clob_buffer || buffer;
end loop;
p_response := clob_buffer;
utl_http.end_response(res);
exception
when utl_http.end_of_body then
p_response := clob_buffer;
utl_http.end_response(res);
when others then null;
dbms_output.put_line(sqlerrm);
dbms_output.put_line(dbms_utility.format_error_backtrace);
utl_http.end_response(res);
end;
exception
when others then
dbms_output.put_line(sqlerrm);
end;
begin
-- init
null;
end test_pkg;
Oracle. Linear Regression
Довольно-таки распространенной статистической задачей анализа ряда данных является поиск линейной регрессии. Oracle предоставляет для данной цели ряд функций. Ниже приведен пример нахождения коэффициентов линейной регрессии y = kx + b:
with
src(y, x) as (
select 3, 0 from dual union all
select 5, 1 from dual union all
select 7, 2 from dual union all
select 9, 3 from dual union all
select 11, 4 from dual union all
select 13, 5 from dual
)
select
regr_slope(y, x) as k,
regr_intercept(y, x) as b
from src
На выходе получим вот такую зависимость:
y = 2x + 3
Вообще коэффициенты линейной регрессии можно найти и аналитически с помощью метода наименьших квадратов по следующим уравнениям:
with
src(y, x) as (
select 3, 0 from dual union all
select 5, 1 from dual union all
select 7, 2 from dual union all
select 9, 3 from dual union all
select 11, 4 from dual union all
select 13, 5 from dual
)
select
regr_slope(y, x) as k,
regr_intercept(y, x) as b
from src
На выходе получим вот такую зависимость:
y = 2x + 3
Вообще коэффициенты линейной регрессии можно найти и аналитически с помощью метода наименьших квадратов по следующим уравнениям:
Nginx with Apache. 504 Gateway time-out
В моем случае Nginx работает в связке с Apache в роли проксирующего веб-сервера. Попробовали выполнить тяжелый скрипт и получили вот такой ответ:
504 Gateway time-out
На стороне Apache ограничений нет. Как выяснилось время ожидания при чтении ответа и время ожидания при передаче запроса у Nginx по умолчанию выставлено в одну минуту. Поэтому для решения данной проблемы достаточно прописать в конфиге (например в location) следующие строки:
server {
...
location / {
...
proxy_read_timeout 600; # время ожидания при чтении ответа
proxy_send_timeout 600; # время ожидания при передаче запроса
...
}
...
}
После перегружаем настройку Nginx
sudo nginx -s reload
504 Gateway time-out
На стороне Apache ограничений нет. Как выяснилось время ожидания при чтении ответа и время ожидания при передаче запроса у Nginx по умолчанию выставлено в одну минуту. Поэтому для решения данной проблемы достаточно прописать в конфиге (например в location) следующие строки:
server {
...
location / {
...
proxy_read_timeout 600; # время ожидания при чтении ответа
proxy_send_timeout 600; # время ожидания при передаче запроса
...
}
...
}
После перегружаем настройку Nginx
sudo nginx -s reload
Subscribe to:
Posts
(
Atom
)