1
0
forked from Alepha/Alepha
This commit is contained in:
2024-07-08 17:06:31 -04:00
parent 7b449fb3e1
commit 6122f3ba80
5 changed files with 696 additions and 0 deletions

207
UniversalAggregate.h Normal file
View File

@ -0,0 +1,207 @@
static_assert( __cplusplus > 2020'99 );
#pragma once
#include <Alepha/Alepha.h>
#include <Alepha/UA_Key.h>
#include <map>
#include <string>
#include <any>
#include <iostream>
#include <vector>
/*!
* @file
* @todo consider dropping string arg versions in favor of just using UA_Key versions (after making conversion constructor not explicit)
* @todo consider how operator >> and << should function. JSON? If so, using what?
* @todo consider [] versions of at
* @todo decide exceptions to throw (especially for not found)
* @todo comment at()
* @todo auto creating option for get (and for general use)
* @todo need to constrain type stored in UniversalAggregate and coerce to those when possible
*/
namespace Alepha::Hydrogen ::detail:: UniversalAggregate_m
{
inline namespace exports
{
class UniversalAggregate;
using MemberType= std::variant< UniversalAggregate, std::string, int, std::vector< UniversalAggregate > >;
class UniversalAggregate
{
private:
// The value could be a UA, a vector of UAs or anything else.
using CoreMap= std::map< std::string, MemberType >;
CoreMap data;
UniversalAggregate &
get( UA_Key key, bool create= false )
{
UniversalAggregate *ret= this;
for( const auto &lv : key.levels )
{
if( std::holds_alternative< std::string >(lv) )
{
if( not ret->data.count( std::get< std::string >( lv ) ) )
{
if( not create ) // throw an error
{
throw std::runtime_error( "desired level not found: " + std::get< std::string >( lv ) );
}
else // create the missing level
{
ret->data[ std::get< std::string >( lv ) ]= UniversalAggregate{};
}
}
ret= &(std::get<UniversalAggregate>(ret->data.at( std::get< std::string >( lv ) ) ) );
continue;
}
}
return *ret;
}
const UniversalAggregate &
get( UA_Key key ) const
{
const UniversalAggregate *ret= this;
for( const auto &lv : key.levels )
{
if( std::holds_alternative< std::string >(lv) )
{
if( not ret->data.count( std::get< std::string >( lv ) ) )
{
throw std::runtime_error( "desired level not found: " + std::get< std::string >( lv ) );
}
ret= &(std::get<UniversalAggregate>(ret->data.at( std::get< std::string >( lv ) ) ) );
continue;
}
}
return *ret;
}
public:
UniversalAggregate()= default;
/*! @brief
* @note direct insert on a vector is not supported. Use at() to obtain a reference to the vector
*/
void
insert( const UA_Key &key, const MemberType &value )
{
if( key.isVector() )
{
throw std::runtime_error( "Operation not supported on vector" );
}
auto& target= get( key.parent(), true );
target.data[ std::get< std::string >( key.levels.back() ) ]= value;
}
/*! @brief
*
*/
void
insert( const std::string &key, const MemberType &value )
{
insert( UA_Key( key ), value );
}
/*! @brief
* @note direct erase on a vector is not supported. Use at() to obtain a reference to the vector
*/
void
erase( const UA_Key &key )
{
if( key.isVector() )
{
throw std::runtime_error( "Operation not supported on vector" );
}
auto& target= get( key.parent() );
target.data.erase( std::get< std::string >( key.levels.back() ) );
return;
}
/*! @brief
*
*/
void
erase( const std::string &key )
{
erase( UA_Key( key ) );
}
/*! @brief
*
*/
const MemberType &
at( const std::string &key ) const
{
return at( UA_Key( key ) );
}
/*! @brief
*
*/
const MemberType &
at( const UA_Key &key ) const
{
if( key.isVector() )
{
throw std::runtime_error( "Operation not supported on vector" );
}
auto& target= get( key.parent() );
return target.data.at( std::get< std::string >( key.levels.back() ) );
}
/*! @brief
*
*/
MemberType &
at( const std::string &key )
{
return at( UA_Key( key ) );
}
/*! @brief
*
*/
MemberType &
at( const UA_Key &key )
{
if( key.isVector() )
{
throw std::runtime_error( "Operation not supported on vector" );
}
auto& target= get( key.parent() );
return target.data.at( std::get< std::string >( key.levels.back() ) );
}
/*! @brief
*
*/
size_t
count( const std::string &key )
{
return 0;
}
/*! @brief
* @note direct count on a vector is not supported. Use at() to obtain a reference to the vector
*/
size_t
count( const UA_Key &key )
{
return 0;
}
};
}
}
namespace Alepha::Hydrogen::inline exports::inline UniversalAggregate_m
{
using namespace detail::UniversalAggregate_m::exports;
}