forked from Alepha/Alepha
UA
This commit is contained in:
207
UniversalAggregate.h
Normal file
207
UniversalAggregate.h
Normal 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user