VTIL-Core/VTIL-Common/util/variant.cpp

202 lines
4.8 KiB
C++
Raw Permalink Normal View History

2020-04-25 05:51:24 +02:00
// Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
2020-07-09 02:43:51 +02:00
// 3. Neither the name of VTIL Project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
2020-04-25 05:51:24 +02:00
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include "variant.hpp"
#include <stdlib.h>
namespace vtil
{
// Copy constructor.
//
variant::variant( const variant& src )
{
// If source is storing a value:
//
2020-04-25 08:06:33 +02:00
if ( src.has_value() )
{
2020-08-18 04:12:32 +02:00
// Inherit the type traits from source.
//
2020-08-18 05:14:57 +02:00
traits = src.traits;
2020-08-18 04:12:32 +02:00
// Invoke copy construction.
//
2020-08-18 05:14:57 +02:00
traits->copy_construct( allocate( traits->size ), src.get_address() );
}
2020-08-18 04:12:32 +02:00
// If source is null, set null.
//
else
{
2020-08-18 05:14:57 +02:00
traits = nullptr;
}
}
2020-08-18 04:12:32 +02:00
// Move constructor.
//
variant::variant( variant&& src )
{
2020-08-18 04:12:32 +02:00
// If source is storing a value:
//
2020-08-18 04:12:32 +02:00
if ( src.has_value() )
{
2020-08-18 04:12:32 +02:00
// Inherit the type traits from source.
//
2020-08-18 05:14:57 +02:00
traits = src.traits;
2020-08-18 04:12:32 +02:00
// If target stores an external pointer:
//
2020-08-18 04:12:32 +02:00
if( !src.is_inline )
{
2020-08-18 04:12:32 +02:00
// Steal the stored external pointer.
//
is_inline = false;
ext = src.ext;
// Mark the source object as null.
//
2020-08-18 05:14:57 +02:00
src.traits = nullptr;
}
else
{
2020-08-18 04:12:32 +02:00
// Invoke move construction.
//
2020-08-18 05:14:57 +02:00
traits->move_construct( allocate( traits->size ), src.get_address() );
}
}
2020-08-18 04:12:32 +02:00
// If source is null, set null.
//
else
{
2020-08-18 05:14:57 +02:00
traits = nullptr;
}
2020-08-18 04:12:32 +02:00
}
2020-08-18 04:12:32 +02:00
// Move assignment.
//
variant& variant::operator=( variant&& vo )
{
// If target is null, reset self.
//
2020-08-18 04:12:32 +02:00
if ( !vo.has_value() )
{
reset();
return *this;
}
2020-08-18 04:12:32 +02:00
// If target stores an external pointer or null:
//
2020-08-18 04:12:32 +02:00
if ( !vo.is_inline )
{
// Swap with current and return.
//
2020-08-18 05:14:57 +02:00
std::swap( as_bytes( *this ), as_bytes( vo ) );
2020-08-18 04:12:32 +02:00
return *this;
}
2020-08-18 05:14:57 +02:00
// If same type, invoke assignment.
2020-08-18 04:12:32 +02:00
//
2020-08-18 05:14:57 +02:00
if ( traits == vo.traits )
2020-08-18 04:12:32 +02:00
{
2020-08-18 05:14:57 +02:00
traits->move_assign( get_address(), vo.get_address() );
2020-08-18 04:12:32 +02:00
return *this;
}
2020-08-18 04:12:32 +02:00
// Otherwise, reset and construct again.
//
2020-08-18 04:12:32 +02:00
reset();
return *new ( this ) variant( std::move( vo ) );
}
2020-08-18 04:12:32 +02:00
// Copy assignment.
//
2020-08-18 04:12:32 +02:00
variant& variant::operator=( const variant& o )
{
// If target is null, reset self.
//
if ( !o.has_value() )
{
reset();
return *this;
}
2020-08-18 05:14:57 +02:00
// If same type, invoke assignment.
//
2020-08-18 05:14:57 +02:00
if ( traits == o.traits )
2020-08-18 04:12:32 +02:00
{
2020-08-18 05:14:57 +02:00
traits->copy_assign( get_address(), o.get_address() );
2020-08-18 04:12:32 +02:00
return *this;
}
// Otherwise, reset and construct again.
//
reset();
return *new ( this ) variant( o );
}
// Allocates the space for an object of the given properties and returns the pointer.
//
2020-08-18 04:12:32 +02:00
void* variant::allocate( size_t size )
{
// Calculate the inline address, if successful reference the inline object.
//
2020-08-18 04:12:32 +02:00
if ( size <= VTIL_VARIANT_INLINE_LIMIT )
{
is_inline = true;
2020-08-18 04:12:32 +02:00
return ( void* ) &inl[ 0 ];
}
2020-08-18 04:12:32 +02:00
// Invoke malloc.
//
else
{
is_inline = false;
2020-08-18 04:12:32 +02:00
return ext = malloc( size );
}
}
2020-08-18 04:12:32 +02:00
// Deletes the currently stored variant.
//
void variant::reset()
{
// If variant is storing any value:
//
if ( has_value() )
{
2020-08-18 04:12:32 +02:00
// Invoke destruction.
//
2020-08-18 05:14:57 +02:00
traits->destruct( get_address() );
2020-08-18 04:12:32 +02:00
// If object was not inlined, invoke free.
//
if ( !is_inline )
free( ext );
2020-08-18 05:14:57 +02:00
// Null traits to indicate null value.
//
2020-08-18 05:14:57 +02:00
traits = nullptr;
}
}
};