From ee7c2505b0ce05e254d1aa597e24bc454b1be293 Mon Sep 17 00:00:00 2001
From: kpetridis <petridkon@gmail.com>
Date: Thu, 28 Apr 2022 18:06:54 +0300
Subject: [PATCH] Finalization of TC[14,2] of ST14

---
 inc/ECSS_Definitions.hpp                      |   2 +-
 inc/Helpers/ForwardControlConfiguration.hpp   |  65 ++--
 .../RealTimeForwardingControlService.hpp      |  21 +-
 .../RealTimeForwardingControlService.cpp      |  54 +--
 test/Services/RealTimeForwardingControl.cpp   | 333 ++++--------------
 5 files changed, 158 insertions(+), 317 deletions(-)

diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp
index bb0eb5a9..52f18244 100644
--- a/inc/ECSS_Definitions.hpp
+++ b/inc/ECSS_Definitions.hpp
@@ -188,7 +188,7 @@ inline const uint8_t ECSSMaxHousekeepingStructures = 10;
  * The max number of controlled application processes
  * @see RealTimeForwardingControlService
  */
-inline const uint8_t ECSSMaxControlledApplications = 5;
+inline const uint8_t ECSSMaxControlledApplicationProcesses = 5;
 
 /**
  * The max number of report type blocking definitions per service type definition in the application process
diff --git a/inc/Helpers/ForwardControlConfiguration.hpp b/inc/Helpers/ForwardControlConfiguration.hpp
index 63a3b313..7a72e176 100644
--- a/inc/Helpers/ForwardControlConfiguration.hpp
+++ b/inc/Helpers/ForwardControlConfiguration.hpp
@@ -3,41 +3,24 @@
 
 #include "ECSS_Definitions.hpp"
 #include "ErrorHandler.hpp"
-#include "etl/vector.h"
-#include "etl/map.h"
 #include "Helpers/Parameter.hpp"
+#include "etl/map.h"
+#include "etl/vector.h"
 
 /**
- * Contains all the necessary configuration types, for the ST[14] 'Real Time Forwarding Control Service'.
+ * Implements the Real Time Forward Control configuration, which includes three separate configurations, Application
+ * Process configuration, Housekeeping configuration and Event Report configuration. These configurations contain
+ * definitions, which indicate whether a telemetry message should be forwarded to the ground station.
+ *
  * @author Konstantinos Petridis <petridkon@gmail.com>
  */
-namespace ForwardControlConfiguration
-{
+
 /**
- * The Application Process configuration. Its architecture is based on a 3-level hierarchy, where the first level
- * is the Application process definitions. Each Application Process definition contains a list of Service Type
- * definitions (level 2) and each Service Type definition contains a list of the Report Type definitions (level 3).
- *
- * 					Applications	[][][]
- * 									 /
- * 			Service types		[][][][][][]
- * 									/
- * 							[][][][][]		Report types
+ * The Application Process configuration. It's basically a map, storing a vector of report type definitions for each
+ * pair of (applicationID, serviceType).
  */
-class ApplicationProcess {
+class ApplicationProcessConfiguration {
 public:
-	/**
-	 * Boolean values for each service type of an application process. See next documentation comment.
-	 */
-	typedef etl::map<uint8_t, bool, ECSSMaxServiceTypeDefinitions> reportsNotEmpty;
-
-	/**
-	 * Translates the absence of report types, in a service type definition. It specifies whether the 'empty' means that
-	 * it has not been filled yet (so we proceed to add new report types) or it is empty because we block every
-	 * report type for the service.
-	 */
-	etl::map<uint8_t, reportsNotEmpty, ECSSMaxControlledApplications> notEmpty;
-
 	/**
 	 * Vector containing the Report Type definitions. Each definition has its unique name of type uint8. For
 	 * example, a Report Type definition could be 'ReportHousekeepingStructures'.
@@ -45,21 +28,29 @@ public:
 	typedef etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> reportTypeDefinitions;
 
 	/**
-	 * Map containing the Service Type definitions. Each Service Type definition is accessed via its key-name, of type
-	 * uint8, for example '20' for the  Parameter Management service. Each Service Type definition, contains the
-	 * list of its own Report Type definitions.
+	 * This is the key for the application process configuration map. It contains a pair with the applicationID and
+	 * the serviceType.
 	 */
-	typedef etl::map<uint8_t, reportTypeDefinitions, ECSSMaxServiceTypeDefinitions> serviceTypeDefinitions;
+	typedef std::pair<uint8_t, uint8_t> appServiceKey;
 
 	/**
-	 * Map containing the Application Process definitions. Each application has its own ID. The ID is used as a
-	 * key to provide access to the list of Service Type definitions, included by the application.
+	 * Map containing the report type definitions. Each application process has its own ID. The combination of the
+	 * application ID and the service type is used as a key to provide access to the list of report type definitions.
+	 *
+	 * @note
+	 * The report type definitions are basically the message types of each service. For example a message type for the
+	 * 'ParameterStatisticsService' (ST04) is 'ParameterStatisticsService::MessageType::ParameterStatisticsReport'. The
+	 * Real Time Forwarding Control Service (ST14) uses this map as a lookup table, to identify whether a requested
+	 * triplet (app->service->message type) is allowed to be forwarded to the ground station via the corresponding virtual
+	 * channel. The requested message type is only forwarded, if the requested application process ID and service type
+	 * already exist in the map, and the requested report type is located in the vector of report types, which corresponds
+	 * to the appID and service type.
 	 */
-	etl::map<uint8_t, serviceTypeDefinitions, ECSSMaxControlledApplications> definitions;
+	etl::map<appServiceKey, reportTypeDefinitions,
+	         ECSSMaxControlledApplicationProcesses * ECSSMaxServiceTypeDefinitions>
+	    definitions;
 
-	ApplicationProcess() = default;
+	ApplicationProcessConfiguration() = default;
 };
 
-} // namespace ForwardControlConfiguration
-
 #endif
diff --git a/inc/Services/RealTimeForwardingControlService.hpp b/inc/Services/RealTimeForwardingControlService.hpp
index b793da2f..1f4ec8fc 100644
--- a/inc/Services/RealTimeForwardingControlService.hpp
+++ b/inc/Services/RealTimeForwardingControlService.hpp
@@ -31,20 +31,35 @@ public:
 	/**
 	 * Contains the Application IDs, controlled by the Service.
 	 */
-	etl::vector<uint8_t, ECSSMaxControlledApplications> controlledApplications;
+	etl::vector<uint8_t, ECSSMaxControlledApplicationProcesses> controlledApplications;
 
 	/**
 	 * The Application Process configuration, containing all the application process, service type and message type
 	 * definitions.
 	 */
-	ForwardControlConfiguration::ApplicationProcess applicationProcessConfiguration;
+	ApplicationProcessConfiguration applicationProcessConfiguration;
 
 private:
+	/**
+	 * Returns true, if the defined application exists in the application process configuration map.
+	 */
+	bool findApplication(uint8_t targetAppID);
+
+	/**
+	 * Returns true, if the defined service type exists in the application process configuration map.
+	 */
+	bool findServiceType(uint8_t applicationID, uint8_t targetService);
+
 	/**
 	 * Checks whether the specified message type already exists in the specified application process and service
 	 * type definition.
 	 */
-	bool reportExistsInAppProcessConfiguration(uint8_t target, uint8_t applicationID, uint8_t serviceType);
+	bool findReportType(uint8_t target, uint8_t applicationID, uint8_t serviceType);
+
+	/**
+	 * Deletes every pair containing the requested application process ID, from the application process configuration.
+	 */
+	void deleteApplicationProcess(uint8_t applicationID);
 
 	/**
 	 * Checks whether the requested application is present in the application process configuration.
diff --git a/src/Services/RealTimeForwardingControlService.cpp b/src/Services/RealTimeForwardingControlService.cpp
index 5a5633a0..d988adb2 100644
--- a/src/Services/RealTimeForwardingControlService.cpp
+++ b/src/Services/RealTimeForwardingControlService.cpp
@@ -1,16 +1,37 @@
 #include "Services/RealTimeForwardingControlService.hpp"
 #include <iostream>
 
-bool RealTimeForwardingControlService::reportExistsInAppProcessConfiguration(uint8_t target, uint8_t applicationID,
-                                                                             uint8_t serviceType) {
-	auto& serviceTypes = applicationProcessConfiguration.definitions[applicationID][serviceType];
+bool RealTimeForwardingControlService::findApplication(uint8_t targetAppID) {
+	auto& definitions = applicationProcessConfiguration.definitions;
+	return std::any_of(std::begin(definitions), std::end(definitions), [targetAppID](auto& definition) { return targetAppID == definition.first.first; });
+}
+
+bool RealTimeForwardingControlService::findServiceType(uint8_t applicationID, uint8_t targetService) {
+	auto& definitions = applicationProcessConfiguration.definitions;
+	return std::any_of(std::begin(definitions), std::end(definitions), [applicationID, targetService](auto& definition) { return applicationID == definition.first.first and targetService == definition.first.second; });
+}
+
+bool RealTimeForwardingControlService::findReportType(uint8_t target, uint8_t applicationID,
+                                                      uint8_t serviceType) {
+	auto appServicePair = std::make_pair(applicationID, serviceType);
+	auto& serviceTypes = applicationProcessConfiguration.definitions[appServicePair];
 	return std::find(serviceTypes.begin(), serviceTypes.end(), target) != serviceTypes.end();
 }
 
+void RealTimeForwardingControlService::deleteApplicationProcess(uint8_t applicationID) {
+	auto& definitions = applicationProcessConfiguration.definitions;
+	auto iter = std::find_if(
+	    std::begin(definitions), std::end(definitions), [applicationID](auto& definition) { return applicationID == definition.first.first; });
+	while (iter != definitions.end()) {
+		definitions.erase(iter);
+		iter = std::find_if(
+		    std::begin(definitions), std::end(definitions), [applicationID](auto& definition) { return applicationID == definition.first.first; });
+	}
+}
+
 bool RealTimeForwardingControlService::applicationExists(Message& request, uint8_t applicationID,
                                                          uint8_t numOfServices) {
-	if (applicationProcessConfiguration.definitions.find(applicationID) ==
-	    applicationProcessConfiguration.definitions.end()) {
+	if (not findApplication(applicationID)) {
 		ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingApplication);
 		for (uint8_t z = 0; z < numOfServices; z++) {
 			request.skipBytes(1);
@@ -24,8 +45,7 @@ bool RealTimeForwardingControlService::applicationExists(Message& request, uint8
 
 bool RealTimeForwardingControlService::serviceTypeExists(Message& request, uint8_t applicationID, uint8_t serviceType,
                                                          uint8_t numOfMessages) {
-	if (applicationProcessConfiguration.definitions[applicationID].find(serviceType) ==
-	    applicationProcessConfiguration.definitions[applicationID].end()) {
+	if (not findServiceType(applicationID, serviceType)) {
 		ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingServiceTypeDefinition);
 		request.skipBytes(numOfMessages);
 		return false;
@@ -35,7 +55,7 @@ bool RealTimeForwardingControlService::serviceTypeExists(Message& request, uint8
 
 bool RealTimeForwardingControlService::reportTypeExists(Message& request, uint8_t applicationID, uint8_t serviceType,
                                                         uint8_t messageType) {
-	if (not reportExistsInAppProcessConfiguration(messageType, applicationID, serviceType)) {
+	if (not findReportType(messageType, applicationID, serviceType)) {
 		ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingReportTypeDefinition);
 		return false;
 	}
@@ -43,21 +63,17 @@ bool RealTimeForwardingControlService::reportTypeExists(Message& request, uint8_
 }
 
 void RealTimeForwardingControlService::deleteServiceRecursive(uint8_t applicationID, uint8_t serviceType) {
-	applicationProcessConfiguration.definitions[applicationID].erase(serviceType);
-	applicationProcessConfiguration.notEmpty[applicationID].erase(serviceType);
-
-	if (applicationProcessConfiguration.definitions[applicationID].empty()) {
-		applicationProcessConfiguration.definitions.erase(applicationID);
-		applicationProcessConfiguration.notEmpty.erase(applicationID);
-	}
+	auto appServicePair = std::make_pair(applicationID, serviceType);
+	applicationProcessConfiguration.definitions.erase(appServicePair);
 }
 
 void RealTimeForwardingControlService::deleteReportRecursive(uint8_t applicationID, uint8_t serviceType,
                                                              uint8_t messageType) {
-	auto& reportTypes = applicationProcessConfiguration.definitions[applicationID][serviceType];
+	auto appServicePair = std::make_pair(applicationID, serviceType);
+	auto& reportTypes = applicationProcessConfiguration.definitions[appServicePair];
 	reportTypes.erase(std::remove(reportTypes.begin(), reportTypes.end(), messageType));
 
-	if (applicationProcessConfiguration.definitions[applicationID][serviceType].empty()) {
+	if (applicationProcessConfiguration.definitions[appServicePair].empty()) {
 		deleteServiceRecursive(applicationID, serviceType);
 	}
 }
@@ -68,7 +84,6 @@ void RealTimeForwardingControlService::deleteReportTypesFromAppProcessConfigurat
 	uint8_t numOfApplications = request.readUint8();
 	if (numOfApplications == 0) {
 		applicationProcessConfiguration.definitions.clear();
-		applicationProcessConfiguration.notEmpty.clear();
 		return;
 	}
 
@@ -80,8 +95,7 @@ void RealTimeForwardingControlService::deleteReportTypesFromAppProcessConfigurat
 			continue;
 		}
 		if (numOfServices == 0) {
-			applicationProcessConfiguration.definitions.erase(applicationID);
-			applicationProcessConfiguration.notEmpty.erase(applicationID);
+			deleteApplicationProcess(applicationID);
 			continue;
 		}
 
diff --git a/test/Services/RealTimeForwardingControl.cpp b/test/Services/RealTimeForwardingControl.cpp
index 55ac0ba9..bb9cc5eb 100644
--- a/test/Services/RealTimeForwardingControl.cpp
+++ b/test/Services/RealTimeForwardingControl.cpp
@@ -1,9 +1,9 @@
 #include <iostream>
-#include "catch2/catch.hpp"
+#include "ECSS_Definitions.hpp"
 #include "Message.hpp"
 #include "ServiceTests.hpp"
-#include "ECSS_Definitions.hpp"
 #include "Services/RealTimeForwardingControlService.hpp"
+#include "catch2/catch.hpp"
 
 RealTimeForwardingControlService& realTimeForwarding = Services.realTimeForwarding;
 
@@ -17,204 +17,48 @@ uint8_t messages1[] = {HousekeepingService::MessageType::HousekeepingPeriodicPro
 uint8_t messages2[] = {EventReportService::MessageType::InformativeEventReport,
                        EventReportService::MessageType::DisabledListEventReport};
 
-void validReportTypes(Message& request) {
-	uint8_t numOfApplications = 1;
-	uint8_t numOfServicesPerApp = 2;
-	uint8_t numOfMessagesPerService = 2;
-
-	request.appendUint8(numOfApplications);
-
-	for (auto appID : applications) {
-		request.appendUint8(appID);
-		request.appendUint8(numOfServicesPerApp);
-
-		for (uint8_t j = 0; j < numOfServicesPerApp; j++) {
-			uint8_t serviceType = services[j];
-			request.appendUint8(serviceType);
-			request.appendUint8(numOfMessagesPerService);
-			uint8_t* messages = (j == 0) ? messages1 : messages2;
-
-			for (uint8_t k = 0; k < numOfMessagesPerService; k++) {
-				request.appendUint8(messages[k]);
-			}
-		}
-	}
-}
-
-void duplicateReportTypes(Message& request) {
-	uint8_t numOfApplications = 1;
-	uint8_t numOfServicesPerApp = 2;
-	uint8_t numOfMessagesPerService = 2;
-
-	request.appendUint8(numOfApplications);
-
-	for (auto appID : applications) {
-		request.appendUint8(appID);
-		request.appendUint8(numOfServicesPerApp);
-
-		for (uint8_t j = 0; j < numOfServicesPerApp; j++) {
-			uint8_t serviceType = services[j];
-			request.appendUint8(serviceType);
-			request.appendUint8(numOfMessagesPerService);
-
-			for (uint8_t k = 0; k < numOfMessagesPerService; k++) {
-				request.appendUint8(messages1[0]);
-			}
-		}
-	}
-}
-
-void validInvalidReportTypes(Message& request) {
-	uint8_t numOfApplications = 3;
-	uint8_t numOfMessagesPerService = 2;
-
-	uint8_t applications2[] = {1, 2, 3};
-	request.appendUint8(numOfApplications);
-
-	for (uint8_t i = 0; i < numOfApplications; i++) {
-		request.appendUint8(applications2[i]);
-		uint8_t numOfServicesPerApp = (i == 0) ? 17 : 2;
-		uint8_t* servicesToPick = (i == 0) ? redundantServices : services;
-		request.appendUint8(numOfServicesPerApp);
-
-		for (uint8_t j = 0; j < numOfServicesPerApp; j++) {
-			uint8_t serviceType = servicesToPick[j];
-			request.appendUint8(serviceType);
-			request.appendUint8(numOfMessagesPerService);
-			uint8_t* messages = (j == 0) ? messages1 : messages2;
-
-			for (uint8_t k = 0; k < numOfMessagesPerService; k++) {
-				request.appendUint8(messages[k]);
-			}
-		}
-	}
-}
-
-void validAllReportsOfService(Message& request) {
-	uint8_t numOfApplications = 1;
-	uint8_t numOfServicesPerApp = 2;
-	uint8_t numOfMessagesPerService = 0;
-
-	request.appendUint8(numOfApplications);
-
-	for (auto appID : applications) {
-		request.appendUint8(appID);
-		request.appendUint8(numOfServicesPerApp);
-
-		for (uint8_t j = 0; j < numOfServicesPerApp; j++) {
-			uint8_t serviceType = services[j];
-			request.appendUint8(serviceType);
-			request.appendUint8(numOfMessagesPerService);
-		}
-	}
+bool findApplication(uint8_t targetAppID) {
+	auto& definitions = realTimeForwarding.applicationProcessConfiguration.definitions;
+	return std::any_of(std::begin(definitions), std::end(definitions), [targetAppID](auto definition) { return targetAppID == definition.first.first; });
 }
 
-void validInvalidAllReportsOfService(Message& request) {
-	uint8_t numOfApplications = 3;
-	uint8_t numOfMessagesPerService = 2;
-
-	uint8_t applications2[] = {1, 2, 3};
-	request.appendUint8(numOfApplications);
-
-	for (uint8_t i = 0; i < numOfApplications; i++) {
-		request.appendUint8(applications2[i]);
-		uint8_t numOfServicesPerApp = (i == 0) ? 17 : 2;
-		uint8_t* servicesToPick = (i == 0) ? redundantServices : services;
-		request.appendUint8(numOfServicesPerApp);
-
-		for (uint8_t j = 0; j < numOfServicesPerApp; j++) {
-			uint8_t serviceType = servicesToPick[j];
-			request.appendUint8(serviceType);
-			uint8_t numOfMessages = (i == 0 or i == 1) ? 0 : numOfMessagesPerService;
-			request.appendUint8(numOfMessages);
-			if (i >= 2) {
-				uint8_t* messages = (j == 0) ? messages1 : messages2;
-
-				for (uint8_t k = 0; k < numOfMessagesPerService; k++) {
-					request.appendUint8(messages[k]);
-				}
-			}
-		}
-	}
-}
-
-void validAllReportsOfApp(Message& request) {
-	uint8_t numOfApplications = 1;
-	uint8_t numOfServicesPerApp = 0;
-
-	request.appendUint8(numOfApplications);
-
-	for (auto appID : applications) {
-		request.appendUint8(appID);
-		request.appendUint8(numOfServicesPerApp);
-	}
-}
-
-void validInvalidAllReportsOfApp(Message& request) {
-	uint8_t numOfApplications = 3;
-	uint8_t numOfMessagesPerService = 2;
-
-	uint8_t applications2[] = {1, 2, 3};
-	request.appendUint8(numOfApplications);
-
-	for (uint8_t i = 0; i < numOfApplications; i++) {
-		request.appendUint8(applications2[i]);
-		uint8_t numOfServicesPerApp = (i == 0 or i == 1) ? 0 : 2;
-		uint8_t* servicesToPick = (i == 0) ? redundantServices : services;
-		request.appendUint8(numOfServicesPerApp);
-
-		if (i >= 2) {
-			for (uint8_t j = 0; j < numOfServicesPerApp; j++) {
-				uint8_t serviceType = servicesToPick[j];
-				request.appendUint8(serviceType);
-				uint8_t numOfMessages = (i == 0 or i == 1) ? 0 : numOfMessagesPerService;
-				request.appendUint8(numOfMessages);
-
-				uint8_t* messages = (j == 0) ? messages1 : messages2;
-
-				for (uint8_t k = 0; k < numOfMessagesPerService; k++) {
-					request.appendUint8(messages[k]);
-				}
-			}
-		}
-	}
+bool findServiceType(uint8_t applicationID, uint8_t targetService) {
+	auto& definitions = realTimeForwarding.applicationProcessConfiguration.definitions;
+	return std::any_of(std::begin(definitions), std::end(definitions), [applicationID, targetService](auto definition) { return applicationID == definition.first.first and targetService == definition.first.second; });
 }
 
 void checkAppProcessConfig() {
 	auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-	auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
 
 	// Check if configuration is initialized properly
-	for (auto appID : applications) {
-		REQUIRE(applicationProcesses.find(appID) != applicationProcesses.end());
-		REQUIRE(isNotEmpty.find(appID) != isNotEmpty.end());
-		REQUIRE(applicationProcesses[appID].size() == 2);
-
-		for (auto serviceType : services) {
-			REQUIRE(applicationProcesses[appID].find(serviceType) != applicationProcesses[appID].end());
-			REQUIRE(applicationProcesses[appID][serviceType].size() == 2);
-			REQUIRE(isNotEmpty[appID].find(serviceType) != isNotEmpty[appID].end());
-
-			for (auto messageType : messages1) {
-				REQUIRE(std::find(applicationProcesses[appID][serviceType].begin(),
-				                  applicationProcesses[appID][serviceType].end(),
-				                  messageType) != applicationProcesses[appID][serviceType].end());
+	for (auto appID: applications) {
+		REQUIRE(findApplication(appID));
+
+		for (auto serviceType: services) {
+			auto appServicePair = std::make_pair(appID, serviceType);
+			REQUIRE(findServiceType(appID, serviceType));
+			REQUIRE(applicationProcesses[appServicePair].size() == 2);
+
+			for (auto messageType: messages1) {
+				REQUIRE(std::find(applicationProcesses[appServicePair].begin(),
+				                  applicationProcesses[appServicePair].end(),
+				                  messageType) != applicationProcesses[appServicePair].end());
 			}
 		}
 	}
 }
 
 void initializeAppProcessConfig() {
-	uint8_t numOfApplications = 1;
-	uint8_t numOfServicesPerApp = 2;
-	uint8_t numOfMessagesPerService = 2;
-
-	for (auto appID : applications) {
-		for (auto serviceType : services) {
-			for (auto messageType : messages1) {
-				realTimeForwarding.applicationProcessConfiguration.definitions[appID][serviceType].push_back(
+	//	uint8_t numOfApplications = 1;
+	//	uint8_t numOfServicesPerApp = 2;
+	//	uint8_t numOfMessagesPerService = 2;
+
+	for (auto appID: applications) {
+		for (auto serviceType: services) {
+			auto appServicePair = std::make_pair(appID, serviceType);
+			for (auto messageType: messages1) {
+				realTimeForwarding.applicationProcessConfiguration.definitions[appServicePair].push_back(
 				    messageType);
-				realTimeForwarding.applicationProcessConfiguration.notEmpty[appID][serviceType] = true;
 			}
 		}
 	}
@@ -223,7 +67,6 @@ void initializeAppProcessConfig() {
 
 void checkAppProcessConfig2() {
 	auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-	auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
 	uint8_t applications2[] = {1, 2, 3};
 
 	uint8_t numOfApplications = 3;
@@ -232,26 +75,24 @@ void checkAppProcessConfig2() {
 	// Check if configuration is initialized properly
 	for (uint8_t i = 0; i < numOfApplications; i++) {
 		uint8_t appID = applications2[i];
-		REQUIRE(applicationProcesses.find(appID) != applicationProcesses.end());
-		REQUIRE(isNotEmpty.find(appID) != isNotEmpty.end());
+		REQUIRE(findApplication(appID));
 
 		uint8_t numOfServices = (i == 2) ? 15 : 2;
 		uint8_t* serviceTypes = (i == 2) ? allServices : services;
-		REQUIRE(applicationProcesses[appID].size() == numOfServices);
 
 		for (uint8_t j = 0; j < numOfServices; j++) {
 			uint8_t serviceType = serviceTypes[j];
 			uint8_t* messages = (i == 2) ? messages2 : messages1;
 
-			REQUIRE(applicationProcesses[appID].find(serviceType) != applicationProcesses[appID].end());
-			REQUIRE(applicationProcesses[appID][serviceType].size() == 2);
-			REQUIRE(isNotEmpty[appID].find(serviceType) != isNotEmpty[appID].end());
+			REQUIRE(findServiceType(appID, serviceType));
+			auto appServicePair = std::make_pair(appID, serviceType);
+			REQUIRE(applicationProcesses[appServicePair].size() == 2);
 
 			for (uint8_t k = 0; k < numOfMessagesPerService; k++) {
 				uint8_t messageType = messages[k];
-				REQUIRE(std::find(applicationProcesses[appID][serviceType].begin(),
-				                  applicationProcesses[appID][serviceType].end(),
-				                  messageType) != applicationProcesses[appID][serviceType].end());
+				REQUIRE(std::find(applicationProcesses[appServicePair].begin(),
+				                  applicationProcesses[appServicePair].end(),
+				                  messageType) != applicationProcesses[appServicePair].end());
 			}
 		}
 	}
@@ -274,9 +115,8 @@ void initializeAppProcessConfig2() {
 
 			for (uint8_t k = 0; k < numOfMessagesPerService; k++) {
 				uint8_t messageType = messages[k];
-				realTimeForwarding.applicationProcessConfiguration.definitions[appID][serviceType].push_back(
+				realTimeForwarding.applicationProcessConfiguration.definitions[std::make_pair(appID, serviceType)].push_back(
 				    messageType);
-				realTimeForwarding.applicationProcessConfiguration.notEmpty[appID][serviceType] = true;
 			}
 		}
 	}
@@ -290,7 +130,7 @@ void serviceNotInApplication(Message& request) {
 
 	request.appendUint8(numOfApplications);
 
-	for (auto appID : applications) {
+	for (auto appID: applications) {
 		request.appendUint8(appID);
 		request.appendUint8(numOfServicesPerApp);
 
@@ -314,7 +154,7 @@ void messageNotInApplication(Message& request) {
 
 	request.appendUint8(numOfApplications);
 
-	for (auto appID : applications) {
+	for (auto appID: applications) {
 		request.appendUint8(appID);
 		request.appendUint8(numOfServicesPerApp);
 
@@ -339,7 +179,7 @@ void deleteValidReportTypes(Message& request) {
 
 	request.appendUint8(numOfApplications);
 
-	for (auto appID : applications) {
+	for (auto appID: applications) {
 		request.appendUint8(appID);
 		request.appendUint8(numOfServicesPerApp);
 
@@ -362,7 +202,7 @@ void deleteReportEmptyService(Message& request) {
 
 	request.appendUint8(numOfApplications);
 
-	for (auto appID : applications) {
+	for (auto appID: applications) {
 		request.appendUint8(appID);
 		request.appendUint8(numOfServicesPerApp);
 
@@ -385,7 +225,7 @@ void deleteReportEmptyApplication(Message& request) {
 
 	request.appendUint8(numOfApplications);
 
-	for (auto appID : applications) {
+	for (auto appID: applications) {
 		request.appendUint8(appID);
 		request.appendUint8(numOfServicesPerApp);
 
@@ -416,7 +256,7 @@ void deleteService(Message& request) {
 	uint8_t numOfMessagesPerService = 0;
 
 	request.appendUint8(numOfApplications);
-	for (auto appID : applications) {
+	for (auto appID: applications) {
 		request.appendUint8(appID);
 		request.appendUint8(numOfServicesPerApp);
 
@@ -434,7 +274,7 @@ void deleteServiceEmptyApplication(Message& request) {
 	uint8_t numOfMessagesPerService = 0;
 
 	request.appendUint8(numOfApplications);
-	for (auto appID : applications) {
+	for (auto appID: applications) {
 		request.appendUint8(appID);
 		request.appendUint8(numOfServicesPerApp);
 
@@ -495,7 +335,6 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 
 		CHECK(ServiceTests::count() == 0);
 		REQUIRE(realTimeForwarding.applicationProcessConfiguration.definitions.empty());
-		REQUIRE(realTimeForwarding.applicationProcessConfiguration.notEmpty.empty());
 
 		resetAppProcessConfiguration();
 		ServiceTests::reset();
@@ -573,14 +412,10 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 
 		CHECK(ServiceTests::count() == 0);
 		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-		auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
 
-		REQUIRE(applicationProcesses[applicationID].size() == 2);
-		REQUIRE(applicationProcesses[applicationID][services[0]].size() == 1);
-		REQUIRE(applicationProcesses[applicationID][services[1]].size() == 1);
-		REQUIRE(isNotEmpty[applicationID].size() == 2);
-		REQUIRE(isNotEmpty[applicationID][services[0]] == true);
-		REQUIRE(isNotEmpty[applicationID][services[1]] == true);
+		REQUIRE(applicationProcesses.size() == 2);
+		REQUIRE(applicationProcesses[std::make_pair(applicationID, services[0])].size() == 1);
+		REQUIRE(applicationProcesses[std::make_pair(applicationID, services[1])].size() == 1);
 
 		resetAppProcessConfiguration();
 		ServiceTests::reset();
@@ -595,16 +430,14 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 		deleteReportEmptyService(request);
 		initializeAppProcessConfig();
 
+		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
+		REQUIRE(realTimeForwarding.applicationProcessConfiguration.definitions.size() == 2);
+
 		MessageParser::execute(request);
 
 		CHECK(ServiceTests::count() == 0);
-		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-		auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
-
-		REQUIRE(applicationProcesses[applicationID].size() == 1);
-		REQUIRE(isNotEmpty[applicationID].size() == 1);
-		REQUIRE(applicationProcesses[applicationID].find(services[1]) != applicationProcesses[applicationID].end());
-		REQUIRE(isNotEmpty[applicationID].find(services[1]) != isNotEmpty[applicationID].end());
+		REQUIRE(applicationProcesses.size() == 1);
+		REQUIRE(findServiceType(applicationID, services[1]));
 
 		resetAppProcessConfiguration();
 		ServiceTests::reset();
@@ -623,10 +456,8 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 
 		CHECK(ServiceTests::count() == 0);
 		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-		auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
 
 		REQUIRE(applicationProcesses.empty());
-		REQUIRE(isNotEmpty.empty());
 
 		resetAppProcessConfiguration();
 		ServiceTests::reset();
@@ -644,10 +475,8 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 
 		CHECK(ServiceTests::count() == 0);
 		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-		auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
 
 		REQUIRE(applicationProcesses.empty());
-		REQUIRE(isNotEmpty.empty());
 
 		resetAppProcessConfiguration();
 		ServiceTests::reset();
@@ -666,12 +495,9 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 
 		CHECK(ServiceTests::count() == 0);
 		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-		auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
 
-		REQUIRE(applicationProcesses[applicationID].size() == 1);
-		REQUIRE(isNotEmpty[applicationID].size() == 1);
-		REQUIRE(applicationProcesses[applicationID].find(services[0]) == applicationProcesses[applicationID].end());
-		REQUIRE(isNotEmpty[applicationID].find(services[0]) == isNotEmpty[applicationID].end());
+		REQUIRE(applicationProcesses.size() == 1);
+		REQUIRE(not findServiceType(applicationID, services[0]));
 
 		resetAppProcessConfiguration();
 		ServiceTests::reset();
@@ -685,15 +511,14 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 		uint8_t applicationID = 1;
 		deleteServiceEmptyApplication(request);
 		initializeAppProcessConfig();
+		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
+		REQUIRE(not applicationProcesses.empty());
 
 		MessageParser::execute(request);
 
 		CHECK(ServiceTests::count() == 0);
-		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-		auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
 
 		REQUIRE(applicationProcesses.empty());
-		REQUIRE(isNotEmpty.empty());
 
 		resetAppProcessConfiguration();
 		ServiceTests::reset();
@@ -719,49 +544,45 @@ TEST_CASE("Delete report types from the Application Process Configuration") {
 		CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::NonExistingReportTypeDefinition) ==
 		      2);
 
-		auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions;
-		auto& isNotEmpty = realTimeForwarding.applicationProcessConfiguration.notEmpty;
+		auto& definitions = realTimeForwarding.applicationProcessConfiguration.definitions;
 
-		REQUIRE(applicationProcesses.size() == 2);
-		for (auto appID : remainingApps) {
-			REQUIRE(applicationProcesses.find(appID) != applicationProcesses.end());
+		REQUIRE(definitions.size() == 16);
+		for (auto appID: remainingApps) {
+			REQUIRE(findApplication(appID));
 		}
+		REQUIRE(std::count_if(std::begin(definitions), std::end(definitions), [&remainingApps](auto& definition) { return std::find(std::begin(remainingApps), std::end(remainingApps), definition.first.first) != std::end(remainingApps); }) == 16);
 
 		// Check for appID = 1
 		uint8_t appID1 = remainingApps[0];
-		REQUIRE(applicationProcesses[appID1].size() == 1);
-		REQUIRE(isNotEmpty[appID1].size() == 1);
-		REQUIRE(applicationProcesses[appID1].find(services[0]) == applicationProcesses[appID1].end());
-		REQUIRE(applicationProcesses[appID1][services[1]].size() == 2);
-		REQUIRE(isNotEmpty[appID1][services[1]] == true);
-
-		for (auto& message : messages1) {
-			REQUIRE(std::find(applicationProcesses[appID1][services[1]].begin(),
-			                  applicationProcesses[appID1][services[1]].end(),
-			                  message) != applicationProcesses[appID1][services[1]].end());
+		REQUIRE(std::count_if(std::begin(definitions), std::end(definitions), [appID1](auto& definition) { return appID1 == definition.first.first; }) == 1);
+		REQUIRE(not findServiceType(appID1, services[0]));
+		auto appServicePair = std::make_pair(appID1, services[1]);
+		REQUIRE(definitions[appServicePair].size() == 2);
+
+		for (auto& message: messages1) {
+			REQUIRE(std::find(definitions[appServicePair].begin(),
+			                  definitions[appServicePair].end(),
+			                  message) != definitions[appServicePair].end());
 		}
 
 		// Check for appID = 2
 		uint8_t appID2 = 2;
-		REQUIRE(applicationProcesses.find(appID2) == applicationProcesses.end());
-		REQUIRE(isNotEmpty.find(appID2) == isNotEmpty.end());
+		REQUIRE(std::count_if(std::begin(definitions), std::end(definitions), [appID2](auto& definition) { return appID2 == definition.first.first; }) == 0);
 
 		// Check for appID = 3
 		uint8_t appID3 = remainingApps[1];
-		REQUIRE(applicationProcesses[appID3].size() == 15);
-		REQUIRE(isNotEmpty[appID3].size() == 15);
+		REQUIRE(std::count_if(std::begin(definitions), std::end(definitions), [appID3](auto& definition) { return appID3 == definition.first.first; }) == 15);
 
 		for (uint8_t i = 0; i < 15; i++) {
 			uint8_t numOfMessages = (i == 0 or i == 7) ? 1 : 2; // we only deleted one report from services 1 and 8
 			uint8_t* messages = (i == 0 or i == 7) ? remainingMessage : messages2;
+			auto appServicePair1 = std::make_pair(appID3, allServices[i]);
 
-			REQUIRE(applicationProcesses[appID3][allServices[i]].size() == numOfMessages);
-			REQUIRE(isNotEmpty[appID3][allServices[i]] == true);
-
+			REQUIRE(definitions[appServicePair1].size() == numOfMessages);
 			for (uint8_t j = 0; j < numOfMessages; j++) {
-				REQUIRE(std::find(applicationProcesses[appID3][allServices[i]].begin(),
-				                  applicationProcesses[appID3][allServices[i]].end(),
-				                  messages[j]) != applicationProcesses[appID3][allServices[i]].end());
+				REQUIRE(std::find(definitions[appServicePair1].begin(),
+				                  definitions[appServicePair1].end(),
+				                  messages[j]) != definitions[appServicePair1].end());
 			}
 		}
 		resetAppProcessConfiguration();
-- 
GitLab