diff --git a/pri/vars.pri b/pri/vars.pri
index 19d698b18..8eb675a6b 100644
--- a/pri/vars.pri
+++ b/pri/vars.pri
@@ -1,7 +1,7 @@
APP_NAME = "RSS Guard"
APP_LOW_NAME = "rssguard"
APP_REVERSE_NAME = "com.github.rssguard"
-APP_LOW_H_NAME = ".rssguard"
+APP_LOW_H_NAME = ".rssguard4"
APP_AUTHOR = "Martin Rotter"
APP_COPYRIGHT = "(C) 2011-2021 $$APP_AUTHOR"
APP_VERSION = "4.0.0"
diff --git a/resources/scripts/7za b/resources/scripts/7za
index 47f412575..9c10723bf 160000
--- a/resources/scripts/7za
+++ b/resources/scripts/7za
@@ -1 +1 @@
-Subproject commit 47f4125753452eff8800dbd6600c5a05540b15d9
+Subproject commit 9c10723bfbaf6cb85107d6ee16e0324e9e487749
diff --git a/resources/sql.qrc b/resources/sql.qrc
index 4377922a7..7d8fa9596 100755
--- a/resources/sql.qrc
+++ b/resources/sql.qrc
@@ -1,47 +1,7 @@
sql/db_init_mysql.sql
- sql/db_update_mysql_1_2.sql
- sql/db_update_mysql_2_3.sql
- sql/db_update_mysql_3_4.sql
- sql/db_update_mysql_4_5.sql
- sql/db_update_mysql_5_6.sql
- sql/db_update_mysql_6_7.sql
- sql/db_update_mysql_7_8.sql
- sql/db_update_mysql_8_9.sql
- sql/db_update_mysql_9_10.sql
- sql/db_update_mysql_10_11.sql
- sql/db_update_mysql_11_12.sql
- sql/db_update_mysql_12_13.sql
- sql/db_update_mysql_13_14.sql
- sql/db_update_mysql_14_15.sql
- sql/db_update_mysql_15_16.sql
- sql/db_update_mysql_16_17.sql
- sql/db_update_mysql_17_18.sql
- sql/db_update_mysql_18_19.sql
- sql/db_update_mysql_19_20.sql
- sql/db_update_mysql_20_21.sql
sql/db_init_sqlite.sql
- sql/db_update_sqlite_1_2.sql
- sql/db_update_sqlite_2_3.sql
- sql/db_update_sqlite_3_4.sql
- sql/db_update_sqlite_4_5.sql
- sql/db_update_sqlite_5_6.sql
- sql/db_update_sqlite_6_7.sql
- sql/db_update_sqlite_7_8.sql
- sql/db_update_sqlite_8_9.sql
- sql/db_update_sqlite_9_10.sql
- sql/db_update_sqlite_10_11.sql
- sql/db_update_sqlite_11_12.sql
- sql/db_update_sqlite_12_13.sql
- sql/db_update_sqlite_13_14.sql
- sql/db_update_sqlite_14_15.sql
- sql/db_update_sqlite_15_16.sql
- sql/db_update_sqlite_16_17.sql
- sql/db_update_sqlite_17_18.sql
- sql/db_update_sqlite_18_19.sql
- sql/db_update_sqlite_19_20.sql
- sql/db_update_sqlite_20_21.sql
\ No newline at end of file
diff --git a/resources/sql/db_init_mysql.sql b/resources/sql/db_init_mysql.sql
index 9acd6e3d0..18d7b050f 100644
--- a/resources/sql/db_init_mysql.sql
+++ b/resources/sql/db_init_mysql.sql
@@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS Information (
inf_value TEXT NOT NULL
);
-- !
-INSERT INTO Information VALUES (1, 'schema_version', '21');
+INSERT INTO Information VALUES (1, 'schema_version', '1');
-- !
CREATE TABLE IF NOT EXISTS Accounts (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
diff --git a/resources/sql/db_init_sqlite.sql b/resources/sql/db_init_sqlite.sql
index 680aa856e..96513ef2d 100644
--- a/resources/sql/db_init_sqlite.sql
+++ b/resources/sql/db_init_sqlite.sql
@@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS Information (
inf_value TEXT NOT NULL
);
-- !
-INSERT INTO Information VALUES (1, 'schema_version', '21');
+INSERT INTO Information VALUES (1, 'schema_version', '1');
-- !
CREATE TABLE IF NOT EXISTS Accounts (
id INTEGER PRIMARY KEY,
diff --git a/resources/sql/db_update_mysql_10_11.sql b/resources/sql/db_update_mysql_10_11.sql
deleted file mode 100755
index 042263f71..000000000
--- a/resources/sql/db_update_mysql_10_11.sql
+++ /dev/null
@@ -1,15 +0,0 @@
-USE ##;
--- !
-CREATE TABLE IF NOT EXISTS GmailAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- app_id TEXT,
- app_key TEXT,
- redirect_url TEXT,
- refresh_token TEXT,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '11' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_11_12.sql b/resources/sql/db_update_mysql_11_12.sql
deleted file mode 100644
index 06175c33e..000000000
--- a/resources/sql/db_update_mysql_11_12.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-USE ##;
--- !
-ALTER TABLE Feeds
-MODIFY url VARCHAR(1000);
--- !
-UPDATE Information SET inf_value = '12' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_12_13.sql b/resources/sql/db_update_mysql_12_13.sql
deleted file mode 100755
index 370aec9cf..000000000
--- a/resources/sql/db_update_mysql_12_13.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-USE ##;
--- !
-ALTER TABLE TtRssAccounts
-ADD COLUMN update_only_unread INTEGER(1) NOT NULL DEFAULT 0 CHECK (update_only_unread >= 0 AND update_only_unread <= 1);
--- !
-UPDATE Information SET inf_value = '13' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_13_14.sql b/resources/sql/db_update_mysql_13_14.sql
deleted file mode 100755
index 215a2367b..000000000
--- a/resources/sql/db_update_mysql_13_14.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-USE ##;
--- !
-ALTER TABLE OwnCloudAccounts
-ADD COLUMN update_only_unread INTEGER(1) NOT NULL DEFAULT 0 CHECK (update_only_unread >= 0 AND update_only_unread <= 1);
--- !
-UPDATE Information SET inf_value = '14' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_14_15.sql b/resources/sql/db_update_mysql_14_15.sql
deleted file mode 100755
index 2abe38cf2..000000000
--- a/resources/sql/db_update_mysql_14_15.sql
+++ /dev/null
@@ -1,18 +0,0 @@
-USE ##;
--- !
-CREATE TABLE IF NOT EXISTS MessageFilters (
- id INTEGER PRIMARY KEY,
- name TEXT NOT NULL CHECK (name != ''),
- script TEXT NOT NULL CHECK (script != '')
-);
--- !
-CREATE TABLE IF NOT EXISTS MessageFiltersInFeeds (
- filter INTEGER NOT NULL,
- feed_custom_id TEXT NOT NULL,
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (filter) REFERENCES MessageFilters (id) ON DELETE CASCADE,
- FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE
-);
--- !
-UPDATE Information SET inf_value = '15' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_15_16.sql b/resources/sql/db_update_mysql_15_16.sql
deleted file mode 100644
index 65a22ec05..000000000
--- a/resources/sql/db_update_mysql_15_16.sql
+++ /dev/null
@@ -1,21 +0,0 @@
-USE ##;
--- !
-CREATE TABLE IF NOT EXISTS Labels (
- id INTEGER PRIMARY KEY,
- name TEXT NOT NULL CHECK (name != ''),
- color VARCHAR(7),
- custom_id TEXT,
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-CREATE TABLE IF NOT EXISTS LabelsInMessages (
- label TEXT NOT NULL, /* Custom ID of label. */
- message TEXT NOT NULL, /* Custom ID of message. */
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE
-);
--- !
-UPDATE Information SET inf_value = '16' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_16_17.sql b/resources/sql/db_update_mysql_16_17.sql
deleted file mode 100644
index d6c3afe99..000000000
--- a/resources/sql/db_update_mysql_16_17.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-USE ##;
--- !
-SET FOREIGN_KEY_CHECKS = 0;
--- !
-ALTER TABLE Labels MODIFY id INTEGER AUTO_INCREMENT;
--- !
-ALTER TABLE MessageFilters MODIFY id INTEGER AUTO_INCREMENT;
--- !
-SET FOREIGN_KEY_CHECKS = 1;
--- !
-UPDATE Information SET inf_value = '17' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_17_18.sql b/resources/sql/db_update_mysql_17_18.sql
deleted file mode 100755
index 9c627fb93..000000000
--- a/resources/sql/db_update_mysql_17_18.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-USE ##;
--- !
-ALTER TABLE Accounts ADD COLUMN proxy_type INTEGER NOT NULL DEFAULT 0 CHECK (proxy_type >= 0);
--- !
-ALTER TABLE Accounts ADD COLUMN proxy_host TEXT;
--- !
-ALTER TABLE Accounts ADD COLUMN proxy_port INTEGER;
--- !
-ALTER TABLE Accounts ADD COLUMN proxy_username TEXT;
--- !
-ALTER TABLE Accounts ADD COLUMN proxy_password TEXT;
--- !
-UPDATE Information SET inf_value = '18' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_18_19.sql b/resources/sql/db_update_mysql_18_19.sql
deleted file mode 100755
index c2a2ec363..000000000
--- a/resources/sql/db_update_mysql_18_19.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE TABLE IF NOT EXISTS GoogleReaderApiAccounts (
- id INTEGER,
- type INTEGER NOT NULL CHECK (type >= 1),
- username TEXT NOT NULL,
- password TEXT,
- url TEXT NOT NULL,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '19' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_19_20.sql b/resources/sql/db_update_mysql_19_20.sql
deleted file mode 100755
index 94b1fe9d7..000000000
--- a/resources/sql/db_update_mysql_19_20.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-CREATE TABLE backup_feeds AS SELECT * FROM Feeds;
--- !
-DROP TABLE Feeds;
--- !
-CREATE TABLE IF NOT EXISTS Feeds (
- id INTEGER AUTO_INCREMENT PRIMARY KEY,
- title TEXT NOT NULL CHECK (title != ''),
- description TEXT,
- date_created BIGINT,
- icon BLOB,
- category INTEGER NOT NULL CHECK (category >= -1),
- encoding TEXT,
- source_type INTEGER,
- url VARCHAR(1000),
- post_process TEXT,
- protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1),
- username TEXT,
- password TEXT,
- update_type INTEGER(1) NOT NULL CHECK (update_type >= 0),
- update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 1),
- type INTEGER,
- account_id INTEGER NOT NULL,
- custom_id TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO Feeds (id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_interval, type, account_id, custom_id)
-SELECT id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_interval, type, account_id, custom_id FROM backup_feeds;
--- !
-DROP TABLE backup_feeds;
--- !
-UPDATE Information SET inf_value = '20' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_1_2.sql b/resources/sql/db_update_mysql_1_2.sql
deleted file mode 100644
index 1df47a23d..000000000
--- a/resources/sql/db_update_mysql_1_2.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE Messages
-ADD COLUMN is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1);
--- !
-UPDATE Information SET inf_value = '2' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_20_21.sql b/resources/sql/db_update_mysql_20_21.sql
deleted file mode 100755
index ed41302db..000000000
--- a/resources/sql/db_update_mysql_20_21.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE TABLE IF NOT EXISTS FeedlyAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- developer_access_token TEXT,
- refresh_token TEXT,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
- update_only_unread INTEGER(1) NOT NULL DEFAULT 0 CHECK (update_only_unread >= 0 AND update_only_unread <= 1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '21' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_2_3.sql b/resources/sql/db_update_mysql_2_3.sql
deleted file mode 100644
index e0b41fb21..000000000
--- a/resources/sql/db_update_mysql_2_3.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-USE ##;
--- !
-ALTER TABLE Messages
-ADD COLUMN enclosures TEXT;
--- !
-UPDATE Information SET inf_value = '3' WHERE inf_key = 'schema_version';
diff --git a/resources/sql/db_update_mysql_3_4.sql b/resources/sql/db_update_mysql_3_4.sql
deleted file mode 100644
index 4338dbd6d..000000000
--- a/resources/sql/db_update_mysql_3_4.sql
+++ /dev/null
@@ -1,70 +0,0 @@
-USE ##;
--- !
-CREATE TABLE Accounts (
- id INTEGER PRIMARY KEY,
- type TEXT NOT NULL
-);
--- !
-INSERT INTO Accounts (type) VALUES ('std-rss');
--- !
-DROP TABLE IF EXISTS FeedsData;
--- !
-CREATE TABLE TtRssAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- password TEXT,
- auth_protected INTEGER(1) NOT NULL DEFAULT 0 CHECK (auth_protected >= 0 AND auth_protected <= 1),
- auth_username TEXT,
- auth_password TEXT,
- url TEXT NOT NULL,
- force_update INTEGER(1) NOT NULL DEFAULT 0 CHECK (force_update >= 0 AND force_update <= 1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-ALTER TABLE Messages
-ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1;
--- !
-ALTER TABLE Messages
-ADD COLUMN custom_id TEXT;
--- !
-ALTER TABLE Messages
-DROP FOREIGN KEY feed;
--- !
-ALTER TABLE Messages
-MODIFY feed TEXT NOT NULL;
--- !
-ALTER TABLE Messages
-MODIFY author TEXT;
--- !
-ALTER TABLE Messages
-MODIFY url TEXT;
--- !
-ALTER TABLE Feeds
-ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1;
--- !
-ALTER TABLE Feeds
-ADD COLUMN custom_id TEXT;
--- !
-ALTER TABLE Feeds
-MODIFY date_created BIGINT;
--- !
-ALTER TABLE Feeds
-MODIFY encoding TEXT;
--- !
-ALTER TABLE Feeds
-MODIFY url VARCHAR(100);
--- !
-ALTER TABLE Feeds
-MODIFY type INTEGER;
--- !
-ALTER TABLE Categories
-ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1;
--- !
-ALTER TABLE Categories
-ADD COLUMN custom_id TEXT;
--- !
-ALTER TABLE Categories
-MODIFY date_created BIGINT;
--- !
-UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_4_5.sql b/resources/sql/db_update_mysql_4_5.sql
deleted file mode 100755
index 2e99e3add..000000000
--- a/resources/sql/db_update_mysql_4_5.sql
+++ /dev/null
@@ -1,25 +0,0 @@
-USE ##;
--- !
-CREATE TABLE IF NOT EXISTS OwnCloudAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- password TEXT,
- url TEXT NOT NULL,
- force_update INTEGER(1) NOT NULL DEFAULT 0 CHECK (force_update >= 0 AND force_update <= 1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Categories
-SET custom_id = (SELECT id FROM Categories t WHERE t.id = Categories.id)
-WHERE Categories.custom_id IS NULL OR Categories.custom_id = '';
--- !
-UPDATE Feeds
-SET custom_id = (SELECT id FROM Feeds t WHERE t.id = Feeds.id)
-WHERE Feeds.custom_id IS NULL OR Feeds.custom_id = '';
--- !
-UPDATE Messages
-SET custom_id = (SELECT id FROM Messages t WHERE t.id = Messages.id)
-WHERE Messages.custom_id IS NULL OR Messages.custom_id = '';
--- !
-UPDATE Information SET inf_value = '5' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_5_6.sql b/resources/sql/db_update_mysql_5_6.sql
deleted file mode 100755
index 6ab572b78..000000000
--- a/resources/sql/db_update_mysql_5_6.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-USE ##;
--- !
-ALTER TABLE Messages
-ADD COLUMN custom_hash TEXT;
--- !
-UPDATE Information SET inf_value = '6' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_6_7.sql b/resources/sql/db_update_mysql_6_7.sql
deleted file mode 100755
index ac8a0a715..000000000
--- a/resources/sql/db_update_mysql_6_7.sql
+++ /dev/null
@@ -1,22 +0,0 @@
--- !
-ALTER DATABASE ##
-CHARACTER SET = utf8mb4
-COLLATE = utf8mb4_unicode_ci;
--- !
-USE ##;
--- !
-ALTER TABLE Messages
-CONVERT TO CHARACTER SET utf8mb4
-COLLATE utf8mb4_unicode_ci;
--- !
-ALTER TABLE Messages
-CHANGE title title TEXT
-CHARACTER SET utf8mb4
-COLLATE utf8mb4_unicode_ci;
--- !
-ALTER TABLE Messages
-CHANGE contents contents TEXT
-CHARACTER SET utf8mb4
-COLLATE utf8mb4_unicode_ci;
--- !
-UPDATE Information SET inf_value = '7' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_7_8.sql b/resources/sql/db_update_mysql_7_8.sql
deleted file mode 100755
index 51f6b37b3..000000000
--- a/resources/sql/db_update_mysql_7_8.sql
+++ /dev/null
@@ -1,25 +0,0 @@
-USE ##;
--- !
-CREATE TABLE IF NOT EXISTS Labels (
- id INTEGER AUTO_INCREMENT PRIMARY KEY,
- account_id INTEGER NOT NULL,
- color_fg TEXT NOT NULL,
- color_bg TEXT NOT NULL,
- title TEXT NOT NULL,
- description TEXT,
- custom_id TEXT,
- custom_hash TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-CREATE TABLE IF NOT EXISTS LabelsInMessages (
- id INTEGER AUTO_INCREMENT PRIMARY KEY,
- message_custom_id TEXT NOT NULL,
- label_custom_id TEXT NOT NULL,
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '8' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_8_9.sql b/resources/sql/db_update_mysql_8_9.sql
deleted file mode 100755
index 56df55084..000000000
--- a/resources/sql/db_update_mysql_8_9.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-USE ##;
--- !
-ALTER TABLE OwnCloudAccounts
-ADD COLUMN msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1);
--- !
-DROP TABLE IF EXISTS Labels;
--- !
-DROP TABLE IF EXISTS LabelsInMessages;
--- !
-UPDATE Information SET inf_value = '9' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_mysql_9_10.sql b/resources/sql/db_update_mysql_9_10.sql
deleted file mode 100755
index b0ba87066..000000000
--- a/resources/sql/db_update_mysql_9_10.sql
+++ /dev/null
@@ -1,15 +0,0 @@
-USE ##;
--- !
-CREATE TABLE IF NOT EXISTS InoreaderAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- app_id TEXT,
- app_key TEXT,
- redirect_url TEXT,
- refresh_token TEXT,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '10' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_10_11.sql b/resources/sql/db_update_sqlite_10_11.sql
deleted file mode 100755
index ef6a5048e..000000000
--- a/resources/sql/db_update_sqlite_10_11.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-CREATE TABLE IF NOT EXISTS GmailAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- app_id TEXT,
- app_key TEXT,
- redirect_url TEXT,
- refresh_token TEXT,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '11' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_11_12.sql b/resources/sql/db_update_sqlite_11_12.sql
deleted file mode 100755
index d535ac102..000000000
--- a/resources/sql/db_update_sqlite_11_12.sql
+++ /dev/null
@@ -1 +0,0 @@
-UPDATE Information SET inf_value = '12' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_12_13.sql b/resources/sql/db_update_sqlite_12_13.sql
deleted file mode 100755
index c896ae79e..000000000
--- a/resources/sql/db_update_sqlite_12_13.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-CREATE TABLE backup_ta AS SELECT * FROM TtRssAccounts;
--- !
-DROP TABLE TtRssAccounts;
--- !
-CREATE TABLE IF NOT EXISTS TtRssAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- password TEXT,
- auth_protected INTEGER(1) NOT NULL CHECK (auth_protected >= 0 AND auth_protected <= 1) DEFAULT 0,
- auth_username TEXT,
- auth_password TEXT,
- url TEXT NOT NULL,
- force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0,
- update_only_unread INTEGER(1) NOT NULL CHECK (update_only_unread >= 0 AND update_only_unread <= 1) DEFAULT 0,
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO TtRssAccounts (id, username, password, auth_protected, auth_username, auth_password, url, force_update, update_only_unread)
-SELECT id, username, password, auth_protected, auth_username, auth_password, url, force_update, 0 FROM backup_ta;
--- !
-DROP TABLE backup_ta;
--- !
-UPDATE Information SET inf_value = '13' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_13_14.sql b/resources/sql/db_update_sqlite_13_14.sql
deleted file mode 100755
index 20dcd8ee2..000000000
--- a/resources/sql/db_update_sqlite_13_14.sql
+++ /dev/null
@@ -1,22 +0,0 @@
-CREATE TABLE backup_ta AS SELECT * FROM OwnCloudAccounts;
--- !
-DROP TABLE OwnCloudAccounts;
--- !
-CREATE TABLE IF NOT EXISTS OwnCloudAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- password TEXT,
- url TEXT NOT NULL,
- force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
- update_only_unread INTEGER(1) NOT NULL CHECK (update_only_unread >= 0 AND update_only_unread <= 1) DEFAULT 0,
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO OwnCloudAccounts (id, username, password, url, force_update, msg_limit, update_only_unread)
-SELECT id, username, password, url, force_update, msg_limit, 0 FROM backup_ta;
--- !
-DROP TABLE backup_ta;
--- !
-UPDATE Information SET inf_value = '14' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_14_15.sql b/resources/sql/db_update_sqlite_14_15.sql
deleted file mode 100755
index 6be1d92c2..000000000
--- a/resources/sql/db_update_sqlite_14_15.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-CREATE TABLE IF NOT EXISTS MessageFilters (
- id INTEGER PRIMARY KEY,
- name TEXT NOT NULL CHECK (name != ''),
- script TEXT NOT NULL CHECK (script != '')
-);
--- !
-CREATE TABLE IF NOT EXISTS MessageFiltersInFeeds (
- filter INTEGER NOT NULL,
- feed_custom_id TEXT NOT NULL,
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (filter) REFERENCES MessageFilters (id) ON DELETE CASCADE,
- FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE
-);
--- !
-UPDATE Information SET inf_value = '15' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_15_16.sql b/resources/sql/db_update_sqlite_15_16.sql
deleted file mode 100644
index bb355d7bc..000000000
--- a/resources/sql/db_update_sqlite_15_16.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-CREATE TABLE IF NOT EXISTS Labels (
- id INTEGER PRIMARY KEY,
- name TEXT NOT NULL CHECK (name != ''),
- color VARCHAR(7),
- custom_id TEXT,
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-CREATE TABLE IF NOT EXISTS LabelsInMessages (
- label TEXT NOT NULL, /* Custom ID of label. */
- message TEXT NOT NULL, /* Custom ID of message. */
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE
-);
--- !
-UPDATE Information SET inf_value = '16' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_16_17.sql b/resources/sql/db_update_sqlite_16_17.sql
deleted file mode 100644
index c9f299b9c..000000000
--- a/resources/sql/db_update_sqlite_16_17.sql
+++ /dev/null
@@ -1 +0,0 @@
-UPDATE Information SET inf_value = '17' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_17_18.sql b/resources/sql/db_update_sqlite_17_18.sql
deleted file mode 100755
index 8891c67e9..000000000
--- a/resources/sql/db_update_sqlite_17_18.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-CREATE TABLE backup_acc AS SELECT * FROM Accounts;
--- !
-PRAGMA foreign_keys = OFF;
--- !
-DROP TABLE Accounts;
--- !
-CREATE TABLE IF NOT EXISTS Accounts (
- id INTEGER PRIMARY KEY,
- type TEXT NOT NULL CHECK (type != ''),
- proxy_type INTEGER NOT NULL CHECK (proxy_type >= 0) DEFAULT 0,
- proxy_host TEXT,
- proxy_port INTEGER,
- proxy_username TEXT,
- proxy_password TEXT
-);
--- !
-INSERT INTO Accounts (id, type) SELECT id, type FROM backup_acc;
--- !
-DROP TABLE backup_acc;
--- !
-PRAGMA foreign_keys = ON;
--- !
-UPDATE Information SET inf_value = '18' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_18_19.sql b/resources/sql/db_update_sqlite_18_19.sql
deleted file mode 100755
index c2a2ec363..000000000
--- a/resources/sql/db_update_sqlite_18_19.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE TABLE IF NOT EXISTS GoogleReaderApiAccounts (
- id INTEGER,
- type INTEGER NOT NULL CHECK (type >= 1),
- username TEXT NOT NULL,
- password TEXT,
- url TEXT NOT NULL,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '19' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_19_20.sql b/resources/sql/db_update_sqlite_19_20.sql
deleted file mode 100755
index 06562eddc..000000000
--- a/resources/sql/db_update_sqlite_19_20.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-CREATE TABLE backup_feeds AS SELECT * FROM Feeds;
--- !
-DROP TABLE Feeds;
--- !
-CREATE TABLE IF NOT EXISTS Feeds (
- id INTEGER PRIMARY KEY,
- title TEXT NOT NULL CHECK (title != ''),
- description TEXT,
- date_created INTEGER,
- icon BLOB,
- category INTEGER NOT NULL CHECK (category >= -1),
- encoding TEXT,
- source_type INTEGER,
- url TEXT,
- post_process TEXT,
- protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1),
- username TEXT,
- password TEXT,
- update_type INTEGER(1) NOT NULL CHECK (update_type >= 0),
- update_interval INTEGER NOT NULL CHECK (update_interval >= 1) DEFAULT 15,
- type INTEGER,
- account_id INTEGER NOT NULL,
- custom_id TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO Feeds (id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_interval, type, account_id, custom_id)
-SELECT id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_interval, type, account_id, custom_id FROM backup_feeds;
--- !
-DROP TABLE backup_feeds;
--- !
-UPDATE Information SET inf_value = '20' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_1_2.sql b/resources/sql/db_update_sqlite_1_2.sql
deleted file mode 100644
index 1df47a23d..000000000
--- a/resources/sql/db_update_sqlite_1_2.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE Messages
-ADD COLUMN is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1);
--- !
-UPDATE Information SET inf_value = '2' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_20_21.sql b/resources/sql/db_update_sqlite_20_21.sql
deleted file mode 100755
index ed41302db..000000000
--- a/resources/sql/db_update_sqlite_20_21.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE TABLE IF NOT EXISTS FeedlyAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- developer_access_token TEXT,
- refresh_token TEXT,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
- update_only_unread INTEGER(1) NOT NULL DEFAULT 0 CHECK (update_only_unread >= 0 AND update_only_unread <= 1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '21' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_2_3.sql b/resources/sql/db_update_sqlite_2_3.sql
deleted file mode 100644
index 326b083b8..000000000
--- a/resources/sql/db_update_sqlite_2_3.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE Messages
-ADD COLUMN enclosures TEXT;
--- !
-UPDATE Information SET inf_value = '3' WHERE inf_key = 'schema_version';
diff --git a/resources/sql/db_update_sqlite_3_4.sql b/resources/sql/db_update_sqlite_3_4.sql
deleted file mode 100644
index bd552c9eb..000000000
--- a/resources/sql/db_update_sqlite_3_4.sql
+++ /dev/null
@@ -1,103 +0,0 @@
-CREATE TABLE Accounts (
- id INTEGER PRIMARY KEY,
- type TEXT NOT NULL
-);
--- !
-INSERT INTO Accounts (type) VALUES ('std-rss');
--- !
-DROP TABLE IF EXISTS FeedsData;
--- !
-CREATE TABLE TtRssAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- password TEXT,
- auth_protected INTEGER(1) NOT NULL CHECK (auth_protected >= 0 AND auth_protected <= 1) DEFAULT 0,
- auth_username TEXT,
- auth_password TEXT,
- url TEXT NOT NULL,
- force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0,
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-CREATE TABLE backup_Messages AS SELECT * FROM Messages;
--- !
-DROP TABLE Messages;
--- !
-CREATE TABLE Messages (
- id INTEGER PRIMARY KEY,
- is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT 0,
- is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT 0,
- is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT 0,
- feed TEXT NOT NULL,
- title TEXT NOT NULL CHECK (title != ''),
- url TEXT,
- author TEXT,
- date_created INTEGER NOT NULL CHECK (date_created != 0),
- contents TEXT,
- is_pdeleted INTEGER(1) NOT NULL CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1) DEFAULT 0,
- enclosures TEXT,
- account_id INTEGER NOT NULL,
- custom_id TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO Messages (id, is_read, is_deleted, is_important, feed, title, url, author, date_created, contents, is_pdeleted, enclosures, account_id)
-SELECT id, is_read, is_deleted, is_important, feed, title, url, author, date_created, contents, is_pdeleted, enclosures, 1 FROM backup_Messages;
--- !
-DROP TABLE backup_Messages;
--- !
-CREATE TABLE backup_Feeds AS SELECT * FROM Feeds;
--- !
-DROP TABLE Feeds;
--- !
-CREATE TABLE Feeds (
- id INTEGER PRIMARY KEY,
- title TEXT NOT NULL CHECK (title != ''),
- description TEXT,
- date_created INTEGER,
- icon BLOB,
- category INTEGER NOT NULL CHECK (category >= -1),
- encoding TEXT,
- url TEXT,
- protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1),
- username TEXT,
- password TEXT,
- update_type INTEGER(1) NOT NULL CHECK (update_type >= 0),
- update_interval INTEGER NOT NULL CHECK (update_interval >= 1) DEFAULT 15,
- type INTEGER,
- account_id INTEGER NOT NULL,
- custom_id TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO Feeds (id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_type, type, account_id)
-SELECT id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_type, type, 1 FROM backup_Feeds;
--- !
-DROP TABLE backup_Feeds;
--- !
-CREATE TABLE backup_Categories AS SELECT * FROM Categories;
--- !
-DROP TABLE Categories;
--- !
-CREATE TABLE Categories (
- id INTEGER PRIMARY KEY,
- parent_id INTEGER NOT NULL,
- title TEXT NOT NULL CHECK (title != ''),
- description TEXT,
- date_created INTEGER,
- icon BLOB,
- account_id INTEGER NOT NULL,
- custom_id TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO Categories (id, parent_id, title, description, date_created, icon, account_id)
-SELECT id, parent_id, title, description, date_created, icon, 1 FROM backup_Categories;
--- !
-DROP TABLE backup_Categories;
--- !
-UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_4_5.sql b/resources/sql/db_update_sqlite_4_5.sql
deleted file mode 100755
index 8367a5c92..000000000
--- a/resources/sql/db_update_sqlite_4_5.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-CREATE TABLE IF NOT EXISTS OwnCloudAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- password TEXT,
- url TEXT NOT NULL,
- force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0,
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Categories
-SET custom_id = (SELECT id FROM Categories t WHERE t.id = Categories.id)
-WHERE Categories.custom_id IS NULL OR Categories.custom_id = '';
--- !
-UPDATE Feeds
-SET custom_id = (SELECT id FROM Feeds t WHERE t.id = Feeds.id)
-WHERE Feeds.custom_id IS NULL OR Feeds.custom_id = '';
--- !
-UPDATE Messages
-SET custom_id = (SELECT id FROM Messages t WHERE t.id = Messages.id)
-WHERE Messages.custom_id IS NULL OR Messages.custom_id = '';
--- !
-UPDATE Information SET inf_value = '5' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_5_6.sql b/resources/sql/db_update_sqlite_5_6.sql
deleted file mode 100755
index f3443019e..000000000
--- a/resources/sql/db_update_sqlite_5_6.sql
+++ /dev/null
@@ -1,30 +0,0 @@
-CREATE TABLE backup_Messages AS SELECT * FROM Messages;
--- !
-DROP TABLE Messages;
--- !
-CREATE TABLE Messages (
- id INTEGER PRIMARY KEY,
- is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT 0,
- is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT 0,
- is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT 0,
- feed TEXT NOT NULL,
- title TEXT NOT NULL CHECK (title != ''),
- url TEXT,
- author TEXT,
- date_created INTEGER NOT NULL CHECK (date_created != 0),
- contents TEXT,
- is_pdeleted INTEGER(1) NOT NULL CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1) DEFAULT 0,
- enclosures TEXT,
- account_id INTEGER NOT NULL,
- custom_id TEXT,
- custom_hash TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO Messages (id, is_read, is_deleted, is_important, feed, title, url, author, date_created, contents, is_pdeleted, enclosures, account_id, custom_id)
-SELECT id, is_read, is_deleted, is_important, feed, title, url, author, date_created, contents, is_pdeleted, enclosures, account_id, custom_id FROM backup_Messages;
--- !
-DROP TABLE backup_Messages;
--- !
-UPDATE Information SET inf_value = '6' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_6_7.sql b/resources/sql/db_update_sqlite_6_7.sql
deleted file mode 100755
index 6214faa87..000000000
--- a/resources/sql/db_update_sqlite_6_7.sql
+++ /dev/null
@@ -1 +0,0 @@
-UPDATE Information SET inf_value = '7' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_7_8.sql b/resources/sql/db_update_sqlite_7_8.sql
deleted file mode 100755
index 25da9dfcb..000000000
--- a/resources/sql/db_update_sqlite_7_8.sql
+++ /dev/null
@@ -1,25 +0,0 @@
-CREATE TABLE IF NOT EXISTS Labels (
- id INTEGER PRIMARY KEY,
- account_id INTEGER NOT NULL,
- color_fg TEXT NOT NULL,
- color_bg TEXT NOT NULL,
- title TEXT NOT NULL,
- description TEXT,
- custom_id TEXT,
- custom_hash TEXT,
-
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-CREATE TABLE IF NOT EXISTS LabelsInMessages (
- id INTEGER PRIMARY KEY,
- message_custom_id TEXT NOT NULL,
- label_custom_id TEXT NOT NULL,
- account_id INTEGER NOT NULL,
-
- FOREIGN KEY (message_custom_id) REFERENCES Messages (custom_id),
- FOREIGN KEY (label_custom_id) REFERENCES Labels (custom_id),
- FOREIGN KEY (account_id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '8' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_8_9.sql b/resources/sql/db_update_sqlite_8_9.sql
deleted file mode 100755
index 357bdf8f5..000000000
--- a/resources/sql/db_update_sqlite_8_9.sql
+++ /dev/null
@@ -1,25 +0,0 @@
-CREATE TABLE backup_oa AS SELECT * FROM OwnCloudAccounts;
--- !
-DROP TABLE OwnCloudAccounts;
--- !
-CREATE TABLE IF NOT EXISTS OwnCloudAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- password TEXT,
- url TEXT NOT NULL,
- force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-INSERT INTO OwnCloudAccounts (id, username, password, url, force_update)
-SELECT id, username, password, url, force_update FROM backup_oa;
--- !
-DROP TABLE backup_oa;
--- !
-DROP TABLE IF EXISTS Labels;
--- !
-DROP TABLE IF EXISTS LabelsInMessages;
--- !
-UPDATE Information SET inf_value = '9' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_9_10.sql b/resources/sql/db_update_sqlite_9_10.sql
deleted file mode 100755
index f7aa98310..000000000
--- a/resources/sql/db_update_sqlite_9_10.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-CREATE TABLE IF NOT EXISTS InoreaderAccounts (
- id INTEGER,
- username TEXT NOT NULL,
- app_id TEXT,
- app_key TEXT,
- redirect_url TEXT,
- refresh_token TEXT,
- msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1),
-
- FOREIGN KEY (id) REFERENCES Accounts (id)
-);
--- !
-UPDATE Information SET inf_value = '10' WHERE inf_key = 'schema_version';
\ No newline at end of file
diff --git a/src/librssguard/3rd-party/boolinq/boolinq.h b/src/librssguard/3rd-party/boolinq/boolinq.h
index c1c25696d..9fcb9ca8b 100755
--- a/src/librssguard/3rd-party/boolinq/boolinq.h
+++ b/src/librssguard/3rd-party/boolinq/boolinq.h
@@ -6,878 +6,960 @@
#include
#include
+#include
#include
#include
-#include
-#include
#include
#include
#include
+#include
//
namespace boolinq {
- struct LinqEndException {};
+ struct LinqEndException {};
- enum BytesDirection {
- BytesFirstToLast,
- BytesLastToFirst,
- };
+ enum BytesDirection {
+ BytesFirstToLast,
+ BytesLastToFirst,
+ };
- enum BitsDirection {
- BitsHighToLow,
- BitsLowToHigh,
- };
+ enum BitsDirection {
+ BitsHighToLow,
+ BitsLowToHigh,
+ };
- template
- class Linq {
- std::function nextFunc;
- S storage;
+ template
+ class Linq {
+ std::function nextFunc;
+ S storage;
public:
- typedef T value_type;
+ typedef T value_type;
- Linq() : nextFunc(), storage()
- {
- }
+ Linq() : nextFunc(), storage()
+ {}
- Linq(S storage, std::function nextFunc) : nextFunc(nextFunc), storage(storage)
- {
- }
+ Linq(S storage, std::function nextFunc) : nextFunc(nextFunc), storage(storage)
+ {}
- T next()
- {
- return nextFunc(storage);
- }
+ T next()
+ {
+ return nextFunc(storage);
+ }
- void for_each_i(std::function apply) const
- {
- Linq linq = *this;
- try {
- for (int i = 0; ; i++) {
- apply(linq.next(), i);
- }
- }
- catch (LinqEndException &) {}
- }
+ void for_each_i(std::function apply) const
+ {
+ Linq linq = *this;
- void for_each(std::function apply) const
- {
- return for_each_i([apply](T value, int) { return apply(value); });
- }
-
- Linq, int>, T> where_i(std::function filter) const
- {
- return Linq, int>, T>(
- std::make_tuple(*this, 0),
- [filter](std::tuple, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- int &index = std::get<1>(tuple);
-
- while (true) {
- T ret = linq.next();
- if (filter(ret, index++)) {
- return ret;
- }
- }
- }
- );
- }
-
- Linq, int>, T> where(std::function filter) const
- {
- return where_i([filter](T value, int) { return filter(value); });
- }
-
- Linq, int>, T> take(int count) const
- {
- return where_i([count](T /*value*/, int i) {
- if (i == count) {
- throw LinqEndException();
- }
- return true;
- });
- }
-
- Linq, int>, T> takeWhile_i(std::function predicate) const
- {
- return where_i([predicate](T value, int i) {
- if (!predicate(value, i)) {
- throw LinqEndException();
- }
- return true;
- });
- }
-
- Linq, int>, T> takeWhile(std::function predicate) const
- {
- return takeWhile_i([predicate](T value, int /*i*/) { return predicate(value); });
- }
-
- Linq, int>, T> skip(int count) const
- {
- return where_i([count](T value, int i) { return i >= count; });
- }
-
- Linq, int, bool>, T> skipWhile_i(std::function predicate) const
- {
- return Linq, int, bool>, T>(
- std::make_tuple(*this, 0, false),
- [predicate](std::tuple, int, bool> &tuple) {
- Linq &linq = std::get<0>(tuple);
- int &index = std::get<1>(tuple);
- bool &flag = std::get<2>(tuple);
-
- if (flag) {
- return linq.next();
- }
- while (true) {
- T ret = linq.next();
- if (!predicate(ret, index++)) {
- flag = true;
- return ret;
- }
- }
- }
- );
- }
-
- Linq, int, bool>, T> skipWhile(std::function predicate) const
- {
- return skipWhile_i([predicate](T value, int /*i*/) { return predicate(value); });
- }
-
- template
- Linq, std::vector, int>, T> append(Types ... newValues) const
- {
- return Linq, std::vector, int>, T>(
- std::make_tuple(*this, std::vector{ newValues... }, -1),
- [](std::tuple, std::vector, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- std::vector &values = std::get<1>(tuple);
- int &index = std::get<2>(tuple);
-
- if (index == -1) {
- try {
- return linq.next();
- }
- catch (LinqEndException &) {
- index = 0;
- }
- }
-
- if (index < values.size()) {
- return values[index++];
- }
-
- throw LinqEndException();
- }
- );
- }
-
- template
- Linq, std::vector, int>, T> prepend(Types ... newValues) const
- {
- return Linq, std::vector, int>, T>(
- std::make_tuple(*this, std::vector{ newValues... }, 0),
- [](std::tuple, std::vector, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- std::vector &values = std::get<1>(tuple);
- int &index = std::get<2>(tuple);
-
- if (index < values.size()) {
- return values[index++];
- }
- return linq.next();
- }
- );
- }
-
- template::type>
- Linq, int>, _TRet> select_i(F apply) const
- {
- return Linq, int>, _TRet>(
- std::make_tuple(*this, 0),
- [apply](std::tuple, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- int &index = std::get<1>(tuple);
-
- return apply(linq.next(), index++);
- }
- );
- }
-
- template::type>
- Linq, int>, _TRet> select(F apply) const
- {
- return select_i([apply](T value, int /*index*/) { return apply(value); });
- }
-
- template
- Linq, int>, TRet> cast() const
- {
- return select_i([](T value, int /*i*/) { return TRet(value); });
- }
-
- template
- Linq, Linq, bool>, T> concat(const Linq & rhs) const
- {
- return Linq, Linq, bool>, T>(
- std::make_tuple(*this, rhs, false),
- [](std::tuple, Linq, bool> &tuple){
- Linq &first = std::get<0>(tuple);
- Linq &second = std::get<1>(tuple);
- bool &flag = std::get<2>(tuple);
-
- if (!flag) {
- try {
- return first.next();
- }
- catch (LinqEndException &) {}
- }
- return second.next();
- }
- );
- }
-
- template<
- typename F,
- typename _TRet = typename std::result_of::type,
- typename _TRetVal = typename _TRet::value_type
- >
- Linq, _TRet, int, bool>, _TRetVal> selectMany_i(F apply) const
- {
- return Linq, _TRet, int, bool>, _TRetVal>(
- std::make_tuple(*this, _TRet(), 0, true),
- [apply](std::tuple, _TRet, int, bool> &tuple) {
- Linq &linq = std::get<0>(tuple);
- _TRet ¤t = std::get<1>(tuple);
- int &index = std::get<2>(tuple);
- bool &finished = std::get<3>(tuple);
-
- while (true) {
- if (finished) {
- current = apply(linq.next(), index++);
- finished = false;
- }
- try {
- return current.next();
- }
- catch (LinqEndException &) {
- finished = true;
- }
- }
- }
- );
- }
-
- template<
- typename F,
- typename _TRet = typename std::result_of::type,
- typename _TRetVal = typename _TRet::value_type
- >
- Linq, _TRet, int, bool>, _TRetVal> selectMany(F apply) const
- {
- return selectMany_i([apply](T value, int index) { return apply(value); });
- }
-
- template<
- typename F,
- typename _TKey = typename std::result_of::type,
- typename _TValue = Linq, int>, T> // where(predicate)
- >
- Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> > groupBy(F apply) const
- {
- return Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> >(
- std::make_tuple(*this, *this, std::unordered_set<_TKey>()),
- [apply](std::tuple, Linq, std::unordered_set<_TKey> > &tuple){
- Linq &linq = std::get<0>(tuple);
- Linq &linqCopy = std::get<1>(tuple);
- std::unordered_set<_TKey> &set = std::get<2>(tuple);
-
- while (true) {
- _TKey key = apply(linq.next());
- if (set.insert(key).second) {
- return std::make_pair(key, linqCopy.where([apply, key](T v){
- return apply(v) == key;
- }));
- }
- }
- }
- );
- }
-
- template::type>
- Linq, std::unordered_set<_TRet> >, T> distinct(F transform) const
- {
- return Linq, std::unordered_set<_TRet> >, T>(
- std::make_tuple(*this, std::unordered_set<_TRet>()),
- [transform](std::tuple, std::unordered_set<_TRet> > &tuple) {
- Linq &linq = std::get<0>(tuple);
- std::unordered_set<_TRet> &set = std::get<1>(tuple);
-
- while (true) {
- T value = linq.next();
- if (set.insert(transform(value)).second) {
- return value;
- }
- }
- }
- );
- }
-
- Linq, std::unordered_set >, T> distinct() const
- {
- return distinct([](T value) { return value; });
- }
-
- template::const_iterator>
- Linq, _TIter, bool>, T> orderBy(F transform) const
- {
- std::vector items = toStdVector();
- std::sort(items.begin(), items.end(), [transform](const T &a, const T &b) {
- return transform(a) < transform(b);
- });
-
- return Linq, _TIter, bool>, T>(
- std::make_tuple(items, _TIter(), false),
- [](std::tuple, _TIter, bool> &tuple) {
- std::vector &vec = std::get<0>(tuple);
- _TIter &it = std::get<1>(tuple);
- bool &flag = std::get<2>(tuple);
-
- if (!flag) {
- flag = true;
- it = vec.cbegin();
- }
- if (it == vec.cend()) {
- throw LinqEndException();
- }
- return *(it++);
- }
- );
- }
-
- Linq, typename std::vector::const_iterator, bool>, T> orderBy() const
- {
- return orderBy([](T value) { return value; });
- }
-
- template::const_reverse_iterator>
- Linq, _TIter, bool>, T> reverse() const
- {
- return Linq, _TIter, bool>, T>(
- std::make_tuple(toStdList(), _TIter(), false),
- [](std::tuple, _TIter, bool> &tuple) {
- std::list &list = std::get<0>(tuple);
- _TIter &it = std::get<1>(tuple);
- bool &flag = std::get<2>(tuple);
-
- if (!flag) {
- flag = true;
- it = list.crbegin();
- }
- if (it == list.crend()) {
- throw LinqEndException();
- }
- return *(it++);
- }
- );
- }
-
- // Aggregators
-
- template
- TRet aggregate(TRet start, std::function accumulate) const
- {
- Linq linq = *this;
- try {
- while (true) {
- start = accumulate(start, linq.next());
- }
- }
- catch (LinqEndException &) {}
- return start;
- }
-
- template::type>
- _TRet sum(F transform) const
- {
- return aggregate<_TRet>(_TRet(), [transform](_TRet accumulator, T value) {
- return accumulator + transform(value);
- });
- }
-
- template
- TRet sum() const
- {
- return sum([](T value) { return TRet(value); });
- }
-
- template::type>
- _TRet avg(F transform) const
- {
- int count = 0;
- _TRet res = sum([transform, &count](T value) {
- count++;
- return transform(value);
- });
- return res / count;
- }
-
- template
- TRet avg() const
- {
- return avg([](T value) { return TRet(value); });
- }
-
- int count() const
- {
- int index = 0;
- for_each([&index](T /*a*/) { index++; });
- return index;
- }
-
- int count(std::function predicate) const
- {
- return where(predicate).count();
- }
-
- int count(const T &item) const
- {
- return count([item](T value) { return item == value; });
- }
-
- // Bool aggregators
-
- bool any(std::function predicate) const
- {
- Linq linq = *this;
- try {
- while (true) {
- if (predicate(linq.next()))
- return true;
- }
- }
- catch (LinqEndException &) {}
- return false;
- }
-
- bool any() const
- {
- return any([](T value) { return static_cast(value); });
- }
-
- bool all(std::function predicate) const
- {
- return !any([predicate](T value) { return !predicate(value); });
- }
-
- bool all() const
- {
- return all([](T value) { return static_cast(value); });
- }
-
- bool contains(const T &item) const
- {
- return any([&item](T value) { return value == item; });
- }
-
- // Election aggregators
-
- T elect(std::function accumulate) const
- {
- T result;
- for_each_i([accumulate, &result](T value, int i) {
- if (i == 0) {
- result = value;
- } else {
- result = accumulate(result, value);
- }
- });
- return result;
- }
-
- template
- T max(F transform) const
- {
- return elect([transform](const T &a, const T &b) {
- return (transform(a) < transform(b)) ? b : a;
- });
- }
-
- T max() const
- {
- return max([](T value) { return value; });
- }
-
- template
- T min(F transform) const
- {
- return elect([transform](const T &a, const T &b) {
- return (transform(a) < transform(b)) ? a : b;
- });
- }
-
- T min() const
- {
- return min([](T value) { return value; });
- }
-
- // Single object returners
-
- T elementAt(int index) const
- {
- return skip(index).next();
- }
-
- T first(std::function predicate) const
- {
- return where(predicate).next();
- }
-
- T first() const
- {
- return Linq(*this).next();
- }
-
- T firstOrDefault(std::function predicate, T const& defaultValue = T()) const
- {
- try {
- return where(predicate).next();
- }
- catch (LinqEndException &) {}
- return defaultValue;
- }
-
- T firstOrDefault(T const& defaultValue = T()) const
- {
- try {
- return Linq(*this).next();
- }
- catch (LinqEndException &) {}
- return defaultValue;
- }
-
- T last(std::function predicate) const
- {
- T res;
- int index = -1;
- where(predicate).for_each_i([&res, &index](T value, int i) {
- res = value;
- index = i;
- });
-
- if (index == -1) {
- throw LinqEndException();
- }
- return res;
- }
-
- T last() const
- {
- return last([](T /*value*/) { return true; });
- }
-
- T lastOrDefault(std::function predicate, T const& defaultValue = T()) const
- {
- T res = defaultValue;
- where(predicate).for_each([&res](T value) {
- res = value;
- });
- return res;
- }
-
- T lastOrDefault(T const& defaultValue = T()) const
- {
- return lastOrDefault([](T /*value*/) { return true; }, defaultValue);
- }
-
- // Export to containers
-
- std::vector toStdVector() const
- {
- std::vector items;
- for_each([&items](T value) {
- items.push_back(value);
- });
- return items;
- }
-
- std::list toStdList() const
- {
- std::list items;
- for_each([&items](T value) {
- items.push_back(value);
- });
- return items;
- }
-
- std::deque toStdDeque() const
- {
- std::deque items;
- for_each([&items](T value) {
- items.push_back(value);
- });
- return items;
- }
-
- std::set toStdSet() const
- {
- std::set items;
- for_each([&items](T value) {
- items.insert(value);
- });
- return items;
- }
-
- std::unordered_set toStdUnorderedSet() const
- {
- std::unordered_set items;
- for_each([&items](T value) {
- items.insert(value);
- });
- return items;
- }
-
- // Bits and bytes
-
- Linq, BytesDirection, T, int>, int> bytes(BytesDirection direction = BytesFirstToLast) const
- {
- return Linq, BytesDirection, T, int>, int>(
- std::make_tuple(*this, direction, T(), sizeof(T)),
- [](std::tuple, BytesDirection, T, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- BytesDirection &bytesDirection = std::get<1>(tuple);
- T &value = std::get<2>(tuple);
- int &index = std::get<3>(tuple);
-
- if (index == sizeof(T)) {
- value = linq.next();
- index = 0;
- }
-
- unsigned char *ptr = reinterpret_cast(&value);
-
- int byteIndex = index;
- if (bytesDirection == BytesLastToFirst) {
- byteIndex = sizeof(T) - 1 - byteIndex;
- }
-
- index++;
- return ptr[byteIndex];
- }
- );
- }
-
- template
- Linq, BytesDirection, int>, TRet> unbytes(BytesDirection direction = BytesFirstToLast) const
- {
- return Linq, BytesDirection, int>, TRet>(
- std::make_tuple(*this, direction, 0),
- [](std::tuple, BytesDirection, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- BytesDirection &bytesDirection = std::get<1>(tuple);
- int &index = std::get<2>(tuple);
-
- TRet value;
- unsigned char *ptr = reinterpret_cast(&value);
-
- for (int i = 0; i < sizeof(TRet); i++) {
- int byteIndex = i;
- if (bytesDirection == BytesLastToFirst) {
- byteIndex = sizeof(TRet) - 1 - byteIndex;
- }
-
- ptr[byteIndex] = linq.next();
- }
-
- return value;
- }
- );
- }
-
- Linq, BytesDirection, BitsDirection, T, int>, int> bits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const
- {
- return Linq, BytesDirection, BitsDirection, T, int>, int>(
- std::make_tuple(*this, bytesDir, bitsDir, T(), sizeof(T) * CHAR_BIT),
- [](std::tuple, BytesDirection, BitsDirection, T, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- BytesDirection &bytesDirection = std::get<1>(tuple);
- BitsDirection &bitsDirection = std::get<2>(tuple);
- T &value = std::get<3>(tuple);
- int &index = std::get<4>(tuple);
-
- if (index == sizeof(T) * CHAR_BIT) {
- value = linq.next();
- index = 0;
- }
-
- unsigned char *ptr = reinterpret_cast(&value);
-
- int byteIndex = index / CHAR_BIT;
- if (bytesDirection == BytesLastToFirst) {
- byteIndex = sizeof(T) - 1 - byteIndex;
- }
-
- int bitIndex = index % CHAR_BIT;
- if (bitsDirection == BitsHighToLow) {
- bitIndex = CHAR_BIT - 1 - bitIndex;
- }
-
- index++;
- return (ptr[byteIndex] >> bitIndex) & 1;
- }
- );
- }
-
- template
- Linq, BytesDirection, BitsDirection, int>, TRet> unbits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const
- {
- return Linq, BytesDirection, BitsDirection, int>, TRet>(
- std::make_tuple(*this, bytesDir, bitsDir, 0),
- [](std::tuple, BytesDirection, BitsDirection, int> &tuple) {
- Linq &linq = std::get<0>(tuple);
- BytesDirection &bytesDirection = std::get<1>(tuple);
- BitsDirection &bitsDirection = std::get<2>(tuple);
- int &index = std::get<3>(tuple);
-
- TRet value = TRet();
- unsigned char *ptr = reinterpret_cast(&value);
-
- for (int i = 0; i < sizeof(TRet) * CHAR_BIT; i++) {
- int byteIndex = i / CHAR_BIT;
- if (bytesDirection == BytesLastToFirst) {
- byteIndex = sizeof(TRet) - 1 - byteIndex;
- }
-
- int bitIndex = i % CHAR_BIT;
- if (bitsDirection == BitsHighToLow) {
- bitIndex = CHAR_BIT - 1 - bitIndex;
- }
-
- ptr[byteIndex] &= ~(1 << bitIndex);
- ptr[byteIndex] |= bool(linq.next()) << bitIndex;
- }
-
- return value;
- }
- );
- }
- };
-
- template
- std::ostream &operator<<(std::ostream &stream, Linq linq)
- {
try {
- while (true) {
- stream << linq.next() << ' ';
- }
+ for (int i = 0; ; i++) {
+ apply(linq.next(), i);
+ }
}
- catch (LinqEndException &) {}
- return stream;
+ catch (LinqEndException&) {}
+ }
+
+ void for_each(std::function apply) const
+ {
+ return for_each_i([apply](T value, int) {
+ return apply(value);
+ });
+ }
+
+ Linq, int>, T> where_i(std::function filter) const
+ {
+ return Linq, int>, T>(
+ std::make_tuple(*this, 0),
+ [filter](std::tuple, int>& tuple) {
+ Linq& linq = std::get<0>(tuple);
+ int& index = std::get<1>(tuple);
+
+ while (true) {
+ T ret = linq.next();
+ if (filter(ret, index++)) {
+ return ret;
+ }
+ }
+ }
+ );
+ }
+
+ Linq, int>, T> where(std::function filter) const
+ {
+ return where_i([filter](T value, int) {
+ return filter(value);
+ });
+ }
+
+ Linq, int>, T> take(int count) const
+ {
+ return where_i([count](T /*value*/, int i) {
+ if (i == count) {
+ throw LinqEndException();
+ }
+
+ return true;
+ });
+ }
+
+ Linq, int>, T> takeWhile_i(std::function predicate) const
+ {
+ return where_i([predicate](T value, int i) {
+ if (!predicate(value, i)) {
+ throw LinqEndException();
+ }
+
+ return true;
+ });
+ }
+
+ Linq, int>, T> takeWhile(std::function predicate) const
+ {
+ return takeWhile_i([predicate](T value, int /*i*/) {
+ return predicate(value);
+ });
+ }
+
+ Linq, int>, T> skip(int count) const
+ {
+ return where_i([count](T, int i) {
+ return i >= count;
+ });
+ }
+
+ Linq, int, bool>, T> skipWhile_i(std::function predicate) const
+ {
+ return Linq, int, bool>, T>(
+ std::make_tuple(*this, 0, false),
+ [predicate](std::tuple, int, bool>& tuple) {
+ Linq& linq = std::get<0>(tuple);
+ int& index = std::get<1>(tuple);
+ bool& flag = std::get<2>(tuple);
+
+ if (flag) {
+ return linq.next();
+ }
+
+ while (true) {
+ T ret = linq.next();
+ if (!predicate(ret, index++)) {
+ flag = true;
+ return ret;
+ }
+ }
+ }
+ );
+ }
+
+ Linq, int, bool>, T> skipWhile(std::function predicate) const
+ {
+ return skipWhile_i([predicate](T value, int /*i*/) {
+ return predicate(value);
+ });
+ }
+
+ template
+ Linq, std::vector, int>, T> append(Types ... newValues) const
+ {
+ return Linq, std::vector, int>, T>(
+ std::make_tuple(*this, std::vector{ newValues ... }, -1),
+ [](std::tuple, std::vector, int>& tuple) {
+ Linq& linq = std::get<0>(tuple);
+ std::vector& values = std::get<1>(tuple);
+ int& index = std::get<2>(tuple);
+
+ if (index == -1) {
+ try {
+ return linq.next();
+ }
+ catch (LinqEndException&) {
+ index = 0;
+ }
+ }
+
+ if (index < values.size()) {
+ return values[index++];
+ }
+
+ throw LinqEndException();
+ }
+ );
+ }
+
+ template
+ Linq, std::vector, int>, T> prepend(Types ... newValues) const
+ {
+ return Linq, std::vector, int>, T>(
+ std::make_tuple(*this, std::vector{ newValues ... }, 0),
+ [](std::tuple, std::vector, int>& tuple) {
+ Linq& linq = std::get<0>(tuple);
+ std::vector& values = std::get<1>(tuple);
+ int& index = std::get<2>(tuple);
+
+ if (index < values.size()) {
+ return values[index++];
+ }
+
+ return linq.next();
+ }
+ );
+ }
+
+ template::type>
+ Linq, int>, _TRet> select_i(F apply) const
+ {
+ return Linq, int>, _TRet>(
+ std::make_tuple(*this, 0),
+ [apply](std::tuple, int>& tuple) {
+ Linq& linq = std::get<0>(tuple);
+ int& index = std::get<1>(tuple);
+
+ return apply(linq.next(), index++);
+ }
+ );
+ }
+
+ template::type>
+ Linq, int>, _TRet> select(F apply) const
+ {
+ return select_i([apply](T value, int /*index*/) {
+ return apply(value);
+ });
+ }
+
+ template
+ Linq, int>, TRet> cast() const
+ {
+ return select_i([](T value, int /*i*/) {
+ return TRet(value);
+ });
+ }
+
+ template
+ Linq, Linq, bool>, T> concat(const Linq& rhs) const
+ {
+ return Linq, Linq, bool>, T>(
+ std::make_tuple(*this, rhs, false),
+ [](std::tuple, Linq, bool>& tuple) {
+ Linq& first = std::get<0>(tuple);
+ Linq& second = std::get<1>(tuple);
+ bool& flag = std::get<2>(tuple);
+
+ if (!flag) {
+ try {
+ return first.next();
+ }
+ catch (LinqEndException&) {}
+ }
+
+ return second.next();
+ }
+ );
+ }
+
+ template<
+ typename F,
+ typename _TRet = typename std::result_of::type,
+ typename _TRetVal = typename _TRet::value_type
+ >
+ Linq, _TRet, int, bool>, _TRetVal> selectMany_i(F apply) const
+ {
+ return Linq, _TRet, int, bool>, _TRetVal>(
+ std::make_tuple(*this, _TRet(), 0, true),
+ [apply](std::tuple, _TRet, int, bool>& tuple) {
+ Linq& linq = std::get<0>(tuple);
+ _TRet& current = std::get<1>(tuple);
+ int& index = std::get<2>(tuple);
+ bool& finished = std::get<3>(tuple);
+
+ while (true) {
+ if (finished) {
+ current = apply(linq.next(), index++);
+ finished = false;
+ }
+
+ try {
+ return current.next();
+ }
+ catch (LinqEndException&) {
+ finished = true;
+ }
+ }
+ }
+ );
+ }
+
+ template<
+ typename F,
+ typename _TRet = typename std::result_of::type,
+ typename _TRetVal = typename _TRet::value_type
+ >
+ Linq, _TRet, int, bool>, _TRetVal> selectMany(F apply) const
+ {
+ return selectMany_i([apply](T value, int) {
+ return apply(value);
+ });
+ }
+
+ template<
+ typename F,
+ typename _TKey = typename std::result_of::type,
+ typename _TValue = Linq, int>, T> // where(predicate)
+ >
+ Linq, Linq, std::unordered_set<_TKey>>, std::pair<_TKey, _TValue>> groupBy(F apply) const
+ {
+ return Linq, Linq, std::unordered_set<_TKey>>, std::pair<_TKey, _TValue>>(
+ std::make_tuple(*this, *this, std::unordered_set<_TKey>()),
+ [apply](std::tuple, Linq, std::unordered_set<_TKey>>& tuple) {
+ Linq& linq = std::get<0>(tuple);
+ Linq& linqCopy = std::get<1>(tuple);
+ std::unordered_set<_TKey>& set = std::get<2>(tuple);
+
+ while (true) {
+ _TKey key = apply(linq.next());
+ if (set.insert(key).second) {
+ return std::make_pair(key, linqCopy.where([apply, key](T v) {
+ return apply(v) == key;
+ }));
+ }
+ }
+ }
+ );
+ }
+
+ template::type>
+ Linq, std::unordered_set<_TRet>>, T> distinct(F transform) const
+ {
+ return Linq, std::unordered_set<_TRet>>, T>(
+ std::make_tuple(*this, std::unordered_set<_TRet>()),
+ [transform](std::tuple