//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Particle/FFMemo.h
//! @brief     Defines class FFMemo.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2026
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifdef SWIG
#error no need to expose this header to Swig
#endif
#ifndef BORNAGAIN_SAMPLE_PARTICLE_FFMEMO_H
#define BORNAGAIN_SAMPLE_PARTICLE_FFMEMO_H

#include <cstddef>
#include <heinz/Complex.h>
#include <heinz/Vectors3D.h>
#include <vector>

class Formfactor;
class WavevectorInfo;

//! Memo for the geometric form factor, shared by particles with identical formfactors
//! (see Refine::shareFormfactors): whichever particle is evaluated first at a given
//! scattering vector stores the result, the others reuse it. Rotation enters through the
//! back-rotated scattering vector that serves as key; material contrast and position phase
//! are applied by the caller. A mesocrystal in reciprocal-space mode attaches a memo even
//! to a single basis particle, since reciprocal lattice vectors recur from pixel to pixel
//! (see Mesocrystal::prepareForComputation).
//!
//! Values live in thread-local tables: threads share no mutable state, hence no locks.

class FFMemo {
public:
    explicit FFMemo(size_t working_set);
    ~FFMemo();

    //! Returns ff evaluated at the given (back-rotated) wavevectors, reusing a
    //! previously memoized value if available.
    complex_t theFF(const WavevectorInfo& wv2, const Formfactor& ff) const;

private:
    //! Direct-mapped hash table: the slot index is the low bits of the hash; one entry per
    //! slot, overwritten on collision. A lookup reads exactly one slot at any load;
    //! overcrowding raises only the recomputation rate, never lookup cost or correctness.
    struct Table {
        struct Entry {
            C3 q;              //!< key: the scattering vector
            complex_t value;   //!< the memoized geometric form factor at q
            bool used = false; //!< false until the slot is filled for the first time
        };
        std::vector<Entry> slots; //!< fixed array of m_capacity entries, allocated once
    };

    //! Returns the calling thread's table for this memo, creating it on first use.
    Table& myTable() const;

    const size_t m_capacity; //!< number of hash slots (power of two)
    const size_t m_id;       //!< process-unique id, assigned at construction; keys the
                             //!< thread-local tables (never reused, unlike the address)
};

#endif // BORNAGAIN_SAMPLE_PARTICLE_FFMEMO_H
