// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package memoize supports memoizing the return values of functions with
// idempotent results that are expensive to compute.
//
// The memoizied result is returned again the next time the function is invoked.
// To prevent excessive memory use, the return values are only remembered
// for as long as they still have a user.
//
// To use this package, build a store and use it to aquire handles with the
// Bind method.
//
package memoize

import (
	"context"
	"runtime"
	"sync"
	"unsafe"
)

// Store binds keys to functions, returning handles that can be used to access
// the functions results.
type Store struct {
	mu sync.Mutex
	// entries is the set of values stored.
	entries map[interface{}]*entry
}

// Function is the type for functions that can be memoized.
// The result must be a pointer.
type Function func(ctx context.Context) interface{}

// Handle is returned from a store when a key is bound to a function.
// It is then used to access the results of that function.
type Handle struct {
	mu       sync.Mutex
	function Function
	entry    *entry
	value    interface{}
}

// entry holds the machinery to manage a function and its result such that
// there is only one instance of the result live at any given time.
type entry struct {
	noCopy
	// mu contols access to the typ and ptr fields
	mu sync.Mutex
	// the calculated value, as stored in an interface{}
	typ, ptr uintptr
	ready    bool
	// wait is used to block until the value is ready
	// will only be non nil if the generator is already running
	wait chan struct{}
}

// Has returns true if they key is currently valid for this store.
func (s *Store) Has(key interface{}) bool {
	s.mu.Lock()
	defer s.mu.Unlock()
	_, found := s.entries[key]
	return found
}

// Delete removes a key from the store, if present.
func (s *Store) Delete(key interface{}) {
	s.mu.Lock()
	defer s.mu.Unlock()
	delete(s.entries, key)
}

// Bind returns a handle for the given key and function.
//
// Each call to bind will generate a new handle.
// All of of the handles for a single key will refer to the same value.
// Only the first handle to get the value will cause the function to be invoked.
// The value will be held for as long as there are handles through which it has been accessed.
// Bind does not cause the value to be generated.
func (s *Store) Bind(key interface{}, function Function) *Handle {
	// panic early if the function is nil
	// it would panic later anyway, but in a way that was much harder to debug
	if function == nil {
		panic("the function passed to bind must not be nil")
	}
	// check if we already have the key
	s.mu.Lock()
	defer s.mu.Unlock()
	e, found := s.entries[key]
	if !found {
		// we have not seen this key before, add a new entry
		if s.entries == nil {
			s.entries = make(map[interface{}]*entry)
		}
		e = &entry{}
		s.entries[key] = e
	}
	return &Handle{
		entry:    e,
		function: function,
	}
}

// Cached returns the value associated with a key.
//
// It cannot cause the value to be generated.
// It will return the cached value, if present.
func (s *Store) Cached(key interface{}) interface{} {
	s.mu.Lock()
	defer s.mu.Unlock()
	e, found := s.entries[key]
	if !found {
		return nil
	}
	e.mu.Lock()
	defer e.mu.Unlock()
	return unref(e)
}

// Cached returns the value associated with a handle.
//
// It will never cause the value to be generated.
// It will return the cached value, if present.
func (h *Handle) Cached() interface{} {
	h.mu.Lock()
	defer h.mu.Unlock()
	if h.value == nil {
		h.entry.mu.Lock()
		defer h.entry.mu.Unlock()
		h.value = unref(h.entry)
	}
	return h.value
}

// Get returns the value associated with a handle.
//
// If the value is not yet ready, the underlying function will be invoked.
// This activates the handle, and it will remember the value for as long as it exists.
// This will cause any other handles for the same key to also return the same value.
func (h *Handle) Get(ctx context.Context) interface{} {
	h.mu.Lock()
	defer h.mu.Unlock()
	if h.function != nil {
		if v, ok := h.entry.get(ctx, h.function); ok {
			h.value = v
			h.function = nil
			h.entry = nil
		}
	}
	return h.value
}

// get is the implementation of Get.
func (e *entry) get(ctx context.Context, f Function) (interface{}, bool) {
	e.mu.Lock()
	// Note: This defer is not paired with the above lock.
	defer e.mu.Unlock()

	// Fast path: If the entry is ready, it already has a value.
	if e.ready {
		return unref(e), true
	}
	// Only begin evaluating the function if no other goroutine is doing so.
	var value interface{}
	if e.wait == nil {
		e.wait = make(chan struct{})
		go func() {
			// Note: We do not hold the lock on the entry in this goroutine.
			//
			// We immediately defer signaling that the entry is ready,
			// since we cannot guarantee that the function, f, will not panic.
			defer func() {
				// Note: We have to hold the entry's lock before returning.
				close(e.wait)
				e.wait = nil
			}()

			// Use the background context to avoid canceling the function.
			// The function cannot be canceled even if the context is canceled
			// because multiple goroutines may depend on it.
			ctx := context.Background()
			value = f(ctx)

			// The function has completed. Update the value in the entry.
			e.mu.Lock()

			// Note: Because this defer will execute before the first defer,
			// we will hold the lock while we update the entry's wait channel.
			defer e.mu.Unlock()
			setref(e, value)
		}()
	}

	// Get a local copy of wait while we still hold the lock.
	wait := e.wait

	// Release the lock while we wait for the value.
	e.mu.Unlock()

	select {
	case <-wait:
		// We should now have a value. Lock the entry, and don't defer an unlock,
		// since we already have done so at the beginning of this function.
		e.mu.Lock()
		result := unref(e)

		// This keep alive makes sure that value is not garbage collected before
		// we call unref and acquire a strong reference to it.
		runtime.KeepAlive(value)
		return result, true
	case <-ctx.Done():
		// The context was canceled, but we have to lock the entry again,
		// since we already deferred an unlock at the beginning of this function.
		e.mu.Lock()
		return nil, false
	}
}

// setref is called to store a weak reference to a value into an entry.
// It assumes that the caller is holding the entry's lock.
func setref(e *entry, value interface{}) interface{} {
	// this is only called when the entry lock is already held
	data := (*[2]uintptr)(unsafe.Pointer(&value))
	// store the value back to the entry as a weak reference
	e.typ, e.ptr = data[0], data[1]
	e.ready = true
	if e.ptr != 0 {
		// Arrange to clear the weak reference when the object is garbage collected.
		runtime.SetFinalizer(value, func(_ interface{}) {
			e.mu.Lock()
			defer e.mu.Unlock()

			// Clear the now-invalid non-pointer.
			e.typ, e.ptr = 0, 0
			// The value is no longer available.
			e.ready = false
		})
	}
	return value
}

// unref returns a strong reference to value stored in the given entry.
// It assumes that the caller is holding the entry's lock.
func unref(e *entry) interface{} {
	// this is only called when the entry lock is already held
	var v interface{}
	data := (*[2]uintptr)(unsafe.Pointer(&v))

	// Note: This approach for computing weak references and converting between
	// weak and strong references would be rendered invalid if Go's runtime
	// changed to allow moving objects on the heap.
	// If such a change were to occur, some modifications would need to be made
	// to this library.
	data[0], data[1] = e.typ, e.ptr
	return v
}
