Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions cpp/Platform.Data.Tests/CLinksSimpleTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <concepts>
#include <vector>
#include <functional>
#include <cstdint>

namespace Platform::Data::Tests
{
// Simple constants for testing
template<typename TLinkAddress>
struct SimpleLinksConstants
{
static constexpr TLinkAddress Continue{1};
static constexpr TLinkAddress Break{2};
};

/// <summary>
/// Simple CLinks concept for testing without complex dependencies
/// </summary>
template<typename T>
concept SimpleCLinks = requires(T links,
const std::vector<typename T::LinkAddressType>& restriction,
const std::vector<typename T::LinkAddressType>& substitution,
const typename T::ReadHandlerType& readHandler,
const typename T::WriteHandlerType& writeHandler)
{
typename T::LinkAddressType;
typename T::ReadHandlerType;
typename T::WriteHandlerType;

// Test that Constants field exists and is accessible
T::Constants;

// Core methods
{ links.Count(restriction) } -> std::convertible_to<typename T::LinkAddressType>;
{ links.Each(restriction, readHandler) } -> std::convertible_to<typename T::LinkAddressType>;
{ links.Create(substitution, writeHandler) } -> std::convertible_to<typename T::LinkAddressType>;
{ links.Update(restriction, substitution, writeHandler) } -> std::convertible_to<typename T::LinkAddressType>;
{ links.Delete(restriction, writeHandler) } -> std::convertible_to<typename T::LinkAddressType>;
};

// Test implementation that should satisfy the concept
struct SimpleLinksImpl
{
using LinkAddressType = std::uint64_t;
using ReadHandlerType = std::function<LinkAddressType(const std::vector<LinkAddressType>&)>;
using WriteHandlerType = std::function<LinkAddressType(const std::vector<LinkAddressType>&, const std::vector<LinkAddressType>&)>;
static constexpr SimpleLinksConstants<LinkAddressType> Constants{};

LinkAddressType Count(const std::vector<LinkAddressType>& restriction) const { return 0; }
LinkAddressType Each(const std::vector<LinkAddressType>& restriction, const ReadHandlerType& handler) const { return 0; }
LinkAddressType Create(const std::vector<LinkAddressType>& substitution, const WriteHandlerType& handler) { return 0; }
LinkAddressType Update(const std::vector<LinkAddressType>& restriction, const std::vector<LinkAddressType>& substitution, const WriteHandlerType& handler) { return 0; }
LinkAddressType Delete(const std::vector<LinkAddressType>& restriction, const WriteHandlerType& handler) { return 0; }
};

// Test implementation that should NOT satisfy the concept (missing methods)
struct IncompleteLinksImpl
{
using LinkAddressType = std::uint64_t;
using ReadHandlerType = std::function<LinkAddressType(const std::vector<LinkAddressType>&)>;
using WriteHandlerType = std::function<LinkAddressType(const std::vector<LinkAddressType>&, const std::vector<LinkAddressType>&)>;
static constexpr SimpleLinksConstants<LinkAddressType> Constants{};

// Only implementing Count method, missing others
LinkAddressType Count(const std::vector<LinkAddressType>& restriction) const { return 0; }
};

// Compile-time tests
static_assert(SimpleCLinks<SimpleLinksImpl>, "SimpleLinksImpl should satisfy SimpleCLinks concept");
static_assert(!SimpleCLinks<IncompleteLinksImpl>, "IncompleteLinksImpl should NOT satisfy SimpleCLinks concept");

// Test with different address types
struct SimpleLinksImpl32
{
using LinkAddressType = std::uint32_t;
using ReadHandlerType = std::function<LinkAddressType(const std::vector<LinkAddressType>&)>;
using WriteHandlerType = std::function<LinkAddressType(const std::vector<LinkAddressType>&, const std::vector<LinkAddressType>&)>;
static constexpr SimpleLinksConstants<LinkAddressType> Constants{};

LinkAddressType Count(const std::vector<LinkAddressType>& restriction) const { return 0; }
LinkAddressType Each(const std::vector<LinkAddressType>& restriction, const ReadHandlerType& handler) const { return 0; }
LinkAddressType Create(const std::vector<LinkAddressType>& substitution, const WriteHandlerType& handler) { return 0; }
LinkAddressType Update(const std::vector<LinkAddressType>& restriction, const std::vector<LinkAddressType>& substitution, const WriteHandlerType& handler) { return 0; }
LinkAddressType Delete(const std::vector<LinkAddressType>& restriction, const WriteHandlerType& handler) { return 0; }
};

static_assert(SimpleCLinks<SimpleLinksImpl32>, "SimpleLinksImpl32 should satisfy SimpleCLinks concept");
}
87 changes: 87 additions & 0 deletions cpp/Platform.Data.Tests/CLinksTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
namespace Platform::Data::Tests
{
template<std::integral TLinkAddress = std::uint64_t, LinksConstants<TLinkAddress> VConstants = LinksConstants<TLinkAddress>{true}, typename TLink = std::vector<TLinkAddress>, typename TReadHandler = std::function<TLinkAddress(TLink)>, typename TWriteHandler = std::function<TLinkAddress(TLink, TLink)>>
struct TestLinksForConcept : public ILinks<LinksOptions<TLinkAddress, VConstants, TLink, TReadHandler, TWriteHandler>>
{
using base = ILinks<LinksOptions<TLinkAddress, VConstants, TLink, TReadHandler, TWriteHandler>>;
using typename base::LinkAddressType;
using typename base::LinkType;
using typename base::WriteHandlerType;
using typename base::ReadHandlerType;
using base::Constants;

LinkAddressType Count(const std::vector<LinkAddressType>& restriction) const override { return 0; };

LinkAddressType Each(const std::vector<LinkAddressType>& restriction, const ReadHandlerType& handler) const override { return 0; };

LinkAddressType Create(const std::vector<LinkAddressType>& restriction, const WriteHandlerType& handler) override { return 0; };

LinkAddressType Update(const std::vector<LinkAddressType>& restriction, const std::vector<LinkAddressType>& substitution, const WriteHandlerType& handler) override { return 0; };

LinkAddressType Delete(const std::vector<LinkAddressType>& restriction, const WriteHandlerType& handler) override { return 0; };
};

// Test that our TestLinksForConcept satisfies the CLinks concept
TEST(CLinksConceptTest, TestLinksForConceptSatisfiesConceptTest)
{
using TLinkAddress = uint64_t;
using TestLinks = TestLinksForConcept<TLinkAddress>;

// This should compile if the concept is satisfied
static_assert(CLinks<TestLinks>, "TestLinksForConcept should satisfy CLinks concept");

// Additional runtime test to ensure instance creation works
TestLinks storage{};
EXPECT_NO_THROW({
std::vector<TLinkAddress> restriction{1};
std::vector<TLinkAddress> substitution{1, 2};

// Test Count method
auto count = storage.Count(restriction);
EXPECT_EQ(count, 0);

// Test Each method
auto eachResult = storage.Each(restriction, [](const std::vector<TLinkAddress>& link){ return TLinkAddress{1}; });
EXPECT_EQ(eachResult, 0);

// Test Create method
auto createResult = storage.Create(substitution, [](const std::vector<TLinkAddress>& before, const std::vector<TLinkAddress>& after){ return TLinkAddress{1}; });
EXPECT_EQ(createResult, 0);

// Test Update method
auto updateResult = storage.Update(restriction, substitution, [](const std::vector<TLinkAddress>& before, const std::vector<TLinkAddress>& after){ return TLinkAddress{1}; });
EXPECT_EQ(updateResult, 0);

// Test Delete method
auto deleteResult = storage.Delete(restriction, [](const std::vector<TLinkAddress>& before, const std::vector<TLinkAddress>& after){ return TLinkAddress{1}; });
EXPECT_EQ(deleteResult, 0);
});
}

// Test that a class missing required methods does not satisfy the concept
struct IncompleteLinks
{
using LinkAddressType = uint64_t;
using ReadHandlerType = std::function<uint64_t(std::vector<uint64_t>)>;
using WriteHandlerType = std::function<uint64_t(std::vector<uint64_t>, std::vector<uint64_t>)>;
static constexpr LinksConstants<uint64_t> Constants{true};

// Missing Count, Each, Create, Update, Delete methods
};

TEST(CLinksConceptTest, IncompleteLinksDoesNotSatisfyConceptTest)
{
// This should not satisfy the concept due to missing methods
static_assert(!CLinks<IncompleteLinks>, "IncompleteLinks should not satisfy CLinks concept");
}

// Test concept with different address types
TEST(CLinksConceptTest, DifferentAddressTypesTest)
{
using TestLinks32 = TestLinksForConcept<uint32_t>;
using TestLinks16 = TestLinksForConcept<uint16_t>;

static_assert(CLinks<TestLinks32>, "TestLinksForConcept<uint32_t> should satisfy CLinks concept");
static_assert(CLinks<TestLinks16>, "TestLinksForConcept<uint16_t> should satisfy CLinks concept");
}
}
94 changes: 94 additions & 0 deletions cpp/Platform.Data/CLinks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#pragma once
#include <concepts>
#include <vector>
#include <type_traits>

namespace Platform::Data
{
/// <summary>
/// <para>Concept that defines the core requirements for ILinks interface implementation.</para>
/// <para>Концепт, который определяет основные требования для реализации интерфейса ILinks.</para>
/// </summary>
/// <remarks>
/// <para>This concept includes only the main methods of ILinks without extensions.</para>
/// <para>Этот концепт включает только основные методы ILinks без расширений.</para>
/// <para>Based on selective polymorphism approach as suggested in the issue comment.</para>
/// <para>Основан на подходе селективного полиморфизма, как предложено в комментарии к задаче.</para>
/// </remarks>
template<typename T>
concept CLinks = requires(T links,
const std::vector<typename T::LinkAddressType>& restriction,
const std::vector<typename T::LinkAddressType>& substitution,
const typename T::ReadHandlerType& readHandler,
const typename T::WriteHandlerType& writeHandler)
{
/// <summary>
/// <para>Link address type used by the implementation.</para>
/// <para>Тип адреса связи, используемый реализацией.</para>
/// </summary>
typename T::LinkAddressType;

/// <summary>
/// <para>Read handler type for traversal operations.</para>
/// <para>Тип обработчика чтения для операций обхода.</para>
/// </summary>
typename T::ReadHandlerType;

/// <summary>
/// <para>Write handler type for modification operations.</para>
/// <para>Тип обработчика записи для операций изменения.</para>
/// </summary>
typename T::WriteHandlerType;

/// <summary>
/// <para>Constants that provide necessary values for effective communication with interface methods.</para>
/// <para>Константы, которые предоставляют необходимые значения для эффективной коммуникации с методами интерфейса.</para>
/// </summary>
T::Constants;

/// <summary>
/// <para>Counts and returns the total number of links in the storage that meet the specified restriction.</para>
/// <para>Подсчитывает и возвращает общее число связей находящихся в хранилище, соответствующих указанному ограничению.</para>
/// </summary>
/// <param name="restriction">Restriction on the contents of links.</param>
/// <returns>The total number of links in the storage that meet the specified restriction.</returns>
{ links.Count(restriction) } -> std::convertible_to<typename T::LinkAddressType>;

/// <summary>
/// <para>Passes through all the links matching the pattern, invoking a handler for each matching link.</para>
/// <para>Выполняет проход по всем связям, соответствующим шаблону, вызывая обработчик для каждой подходящей связи.</para>
/// </summary>
/// <param name="restriction">Restriction on the contents of links.</param>
/// <param name="handler">A handler for each matching link.</param>
/// <returns>Constants.Continue if the pass through the links was not interrupted, and Constants.Break otherwise.</returns>
{ links.Each(restriction, readHandler) } -> std::convertible_to<typename T::LinkAddressType>;

/// <summary>
/// <para>Creates a link.</para>
/// <para>Создаёт связь.</para>
/// </summary>
/// <param name="substitution">The content of a new link.</param>
/// <param name="handler">A function to handle each executed change.</param>
/// <returns>Constants.Continue if all executed changes are handled, Constants.Break if processing is stopped.</returns>
{ links.Create(substitution, writeHandler) } -> std::convertible_to<typename T::LinkAddressType>;

/// <summary>
/// <para>Updates links that match the specified restriction with new content.</para>
/// <para>Обновляет связи, соответствующие указанному ограничению, новым содержимым.</para>
/// </summary>
/// <param name="restriction">Restriction on the contents of links to update.</param>
/// <param name="substitution">New content for the links.</param>
/// <param name="handler">A function to handle each executed change.</param>
/// <returns>Constants.Continue if all executed changes are handled, Constants.Break if processing is stopped.</returns>
{ links.Update(restriction, substitution, writeHandler) } -> std::convertible_to<typename T::LinkAddressType>;

/// <summary>
/// <para>Deletes links that match the specified restriction.</para>
/// <para>Удaляет связи соответствующие указанному ограничению.</para>
/// </summary>
/// <param name="restriction">Restriction on the content of links to delete.</param>
/// <param name="handler">A function to handle each executed change.</param>
/// <returns>Constants.Continue if all executed changes are handled, Constants.Break if processing is stopped.</returns>
{ links.Delete(restriction, writeHandler) } -> std::convertible_to<typename T::LinkAddressType>;
};
}
1 change: 1 addition & 0 deletions cpp/Platform.Data/Platform.Data.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
#include "LinksOptions.h"
#include "LinksConstantsExtensions.h"
#include "ILinks.h"
#include "CLinks.h"

#include "ILinksExtensions.h"
Loading