<commit_before>/*
 * reference.cpp
 *
 *  Created on: Apr 12, 2016
 *      Author: zmij
 */

#include <wire/core/reference.hpp>

#include <iostream>
#include <sstream>

#include <wire/core/connector.hpp>
#include <wire/core/locator.hpp>

namespace wire {
namespace core {

bool
operator == (reference_data const& lhs, reference_data const& rhs)
{
    return lhs.object_id == rhs.object_id &&
            lhs.facet == rhs.facet &&
            lhs.adapter == rhs.adapter &&
            lhs.endpoints == rhs.endpoints;
}
bool
operator != (reference_data const& lhs, reference_data const& rhs)
{
    return !(lhs == rhs);
}
bool
operator < (reference_data const& lhs, reference_data const& rhs)
{
    return lhs.object_id < rhs.object_id &&
            lhs.facet < rhs.facet &&
            lhs.adapter < rhs.adapter &&
            lhs.endpoints < rhs.endpoints;
}

reference_data
operator "" _wire_ref(char const* str, ::std::size_t sz)
{
    ::std::string literal{str, sz};
    ::std::istringstream is{literal};
    reference_data ref;
    if (!(is >> ref))
        throw ::std::runtime_error{"Invalid ::wire::core::reference_data literal " + literal};
    return ref;
}

::std::size_t
id_facet_hash(reference_data const& ref)
{
    auto h = hash(ref.object_id);
    return (h << 1) ^ hash(ref.facet);
}

::std::size_t
hash(reference_data const& ref)
{
    auto h = id_facet_hash(ref);
    if (ref.adapter.is_initialized())
        h = (h << 1) ^ hash(ref.adapter.get());
    h = (h << 1) ^ hash(ref.endpoints);
    return h;
}

//----------------------------------------------------------------------------
//      Base reference implementation
//----------------------------------------------------------------------------
reference_ptr
reference::create_reference(connector_ptr cnctr, reference_data const& ref_data)
{
    if (!ref_data.endpoints.empty()) {
        // Find a connection or create a new one
        return
            ::std::make_shared< fixed_reference >(cnctr, ref_data);
    }
    return ::std::make_shared< floating_reference >(cnctr, ref_data);
}

bool
reference::is_local() const
{
    if (local_object_cache_.lock())
        return true;
    return get_connector()->is_local(*this);
}

reference::local_servant
reference::get_local_object() const
{
    auto obj = local_object_cache_.lock();
    if (!obj) {
        auto loc_srv = get_connector()->find_local_servant(*this);
        obj = loc_srv.first;
        local_object_cache_ = obj;
        adapter_cache_      = loc_srv.second;
    }
    return {obj, adapter_cache_.lock()};
}

connection_ptr
reference::get_connection() const
{
    auto future = get_connection_async(true);
    return future.get();
}

connector_ptr
reference::get_connector() const
{
    auto cnctr = connector_.lock();
    if (!cnctr)
        throw errors::runtime_error{ "Connector already destroyed" };
    return cnctr;
}

asio_config::io_service_ptr
reference::io_service() const
{
    return get_connector()->io_service();
}

locator_prx
reference::get_locator() const
{
    return ref_.locator;
}

void
reference::set_locator(locator_prx lctr)
{
    ref_.locator = lctr;
}

void
reference::set_locator(reference_data const& loc_ref)
{
    ref_.locator = unchecked_cast<locator_proxy>(get_connector()->make_proxy(loc_ref));
}

//----------------------------------------------------------------------------
//      Fixed reference implementation
//----------------------------------------------------------------------------
fixed_reference::fixed_reference(connector_ptr cn, reference_data const& ref)
    : reference{cn, ref}, current_{ref_.endpoints.end()}
{
    if (ref_.endpoints.empty())
        throw errors::runtime_error{ "Reference endpoint list is empty" };
}

fixed_reference::fixed_reference(fixed_reference const& rhs)
    : reference{rhs},
      connection_{rhs.connection_.lock()},
      current_{ref_.endpoints.end()}
{
}

fixed_reference::fixed_reference(fixed_reference&& rhs)
    : reference{::std::move(rhs)},
      connection_{rhs.connection_.lock()},
      current_{ref_.endpoints.end()}
{
}

void
fixed_reference::get_connection_async( connection_callback on_get,
        functional::exception_callback on_error,
        bool sync) const
{
    connection_ptr conn = connection_.lock();
    if (!conn) {
        {
            lock_guard lock{mutex_};
            conn = connection_.lock();
        }
        if (conn) {
            try {
                on_get(conn);
            } catch (...) {}
            return;
        }
        connector_ptr cntr = get_connector();
        if (current_ == ref_.endpoints.end()) {
            current_ = ref_.endpoints.begin();
        }
        auto _this = shared_this<fixed_reference>();
        cntr->get_outgoing_connection_async(
            *current_++,
            [_this, on_get, on_error](connection_ptr c)<commit_msg>Fix races with incrementing enpoint iterator<commit_after>/*
 * reference.cpp
 *
 *  Created on: Apr 12, 2016
 *      Author: zmij
 */

#include <wire/core/reference.hpp>

#include <iostream>
#include <sstream>

#include <wire/core/connector.hpp>
#include <wire/core/locator.hpp>

namespace wire {
namespace core {

bool
operator == (reference_data const& lhs, reference_data const& rhs)
{
    return lhs.object_id == rhs.object_id &&
            lhs.facet == rhs.facet &&
            lhs.adapter == rhs.adapter &&
            lhs.endpoints == rhs.endpoints;
}
bool
operator != (reference_data const& lhs, reference_data const& rhs)
{
    return !(lhs == rhs);
}
bool
operator < (reference_data const& lhs, reference_data const& rhs)
{
    return lhs.object_id < rhs.object_id &&
            lhs.facet < rhs.facet &&
            lhs.adapter < rhs.adapter &&
            lhs.endpoints < rhs.endpoints;
}

reference_data
operator "" _wire_ref(char const* str, ::std::size_t sz)
{
    ::std::string literal{str, sz};
    ::std::istringstream is{literal};
    reference_data ref;
    if (!(is >> ref))
        throw ::std::runtime_error{"Invalid ::wire::core::reference_data literal " + literal};
    return ref;
}

::std::size_t
id_facet_hash(reference_data const& ref)
{
    auto h = hash(ref.object_id);
    return (h << 1) ^ hash(ref.facet);
}

::std::size_t
hash(reference_data const& ref)
{
    auto h = id_facet_hash(ref);
    if (ref.adapter.is_initialized())
        h = (h << 1) ^ hash(ref.adapter.get());
    h = (h << 1) ^ hash(ref.endpoints);
    return h;
}

//----------------------------------------------------------------------------
//      Base reference implementation
//----------------------------------------------------------------------------
reference_ptr
reference::create_reference(connector_ptr cnctr, reference_data const& ref_data)
{
    if (!ref_data.endpoints.empty()) {
        // Find a connection or create a new one
        return
            ::std::make_shared< fixed_reference >(cnctr, ref_data);
    }
    return ::std::make_shared< floating_reference >(cnctr, ref_data);
}

bool
reference::is_local() const
{
    if (local_object_cache_.lock())
        return true;
    return get_connector()->is_local(*this);
}

reference::local_servant
reference::get_local_object() const
{
    auto obj = local_object_cache_.lock();
    if (!obj) {
        auto loc_srv = get_connector()->find_local_servant(*this);
        obj = loc_srv.first;
        local_object_cache_ = obj;
        adapter_cache_      = loc_srv.second;
    }
    return {obj, adapter_cache_.lock()};
}

connection_ptr
reference::get_connection() const
{
    auto future = get_connection_async(true);
    return future.get();
}

connector_ptr
reference::get_connector() const
{
    auto cnctr = connector_.lock();
    if (!cnctr)
        throw errors::runtime_error{ "Connector already destroyed" };
    return cnctr;
}

asio_config::io_service_ptr
reference::io_service() const
{
    return get_connector()->io_service();
}

locator_prx
reference::get_locator() const
{
    return ref_.locator;
}

void
reference::set_locator(locator_prx lctr)
{
    ref_.locator = lctr;
}

void
reference::set_locator(reference_data const& loc_ref)
{
    ref_.locator = unchecked_cast<locator_proxy>(get_connector()->make_proxy(loc_ref));
}

//----------------------------------------------------------------------------
//      Fixed reference implementation
//----------------------------------------------------------------------------
fixed_reference::fixed_reference(connector_ptr cn, reference_data const& ref)
    : reference{cn, ref}, current_{ref_.endpoints.end()}
{
    if (ref_.endpoints.empty())
        throw errors::runtime_error{ "Reference endpoint list is empty" };
}

fixed_reference::fixed_reference(fixed_reference const& rhs)
    : reference{rhs},
      connection_{rhs.connection_.lock()},
      current_{ref_.endpoints.end()}
{
}

fixed_reference::fixed_reference(fixed_reference&& rhs)
    : reference{::std::move(rhs)},
      connection_{rhs.connection_.lock()},
      current_{ref_.endpoints.end()}
{
}

void
fixed_reference::get_connection_async( connection_callback on_get,
        functional::exception_callback on_error,
        bool sync) const
{
    connection_ptr conn = connection_.lock();
    if (!conn) {
        connector_ptr cntr = get_connector();
        endpoint ep;
        {
            lock_guard lock{mutex_};
            conn = connection_.lock();
            if (current_ == ref_.endpoints.end()) {
                current_ = ref_.endpoints.begin();
            }
            ep = *current_++;
        }
        if (conn) {
            try {
                on_get(conn);
            } catch (...) {}
            return;
        }
        auto _this = shared_this<fixed_reference>();
        cntr->get_outgoing_connection_async(
            ep,
            [_this, on_get, on_error](connection_ptr c)
{'fraction_non_alphanumeric': 0.18632968382277704, 'fraction_numerical': 0.0018418090657935128, 'mean_word_length': 2.440337909186906, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5496600', 'n_tokens_mistral': 2955, 'n_tokens_neox': 2957, 'n_words': 600}