/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef NB_MEMORY_TRACKER_HELPERS_H_
#define NB_MEMORY_TRACKER_HELPERS_H_

#include <map>
#include <vector>

#include "nb/analytics/memory_tracker.h"
#include "nb/atomic.h"
#include "nb/simple_thread.h"
#include "starboard/mutex.h"
#include "starboard/thread.h"
#include "starboard/types.h"
#include "starboard/log.h"

namespace nb {
namespace analytics {

class AllocationGroup;
class AllocationRecord;

template <typename Type>
class ThreadLocalPointer {
 public:
  ThreadLocalPointer() {
    slot_ = SbThreadCreateLocalKey(NULL);  // No destructor for pointer.
    SB_DCHECK(kSbThreadLocalKeyInvalid != slot_);
  }

  ~ThreadLocalPointer() { SbThreadDestroyLocalKey(slot_); }

  Type* Get() const {
    void* ptr = SbThreadGetLocalValue(slot_);
    Type* type_ptr = static_cast<Type*>(ptr);
    return type_ptr;
  }

  void Set(Type* ptr) {
    void* void_ptr = static_cast<void*>(ptr);
    SbThreadSetLocalValue(slot_, void_ptr);
  }

 private:
  SbThreadLocalKey slot_;
  SB_DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);
};

class ThreadLocalBoolean {
 public:
  ThreadLocalBoolean() : default_value_(false) {}
  explicit ThreadLocalBoolean(bool default_value)
      : default_value_(default_value) {}
  ~ThreadLocalBoolean() {}

  bool Get() const {
    bool val = tlp_.Get() != NULL;
    return val ^ default_value_;
  }

  void Set(bool val) {
    val = val ^ default_value_;
    tlp_.Set(val ? TruePointer() : FalsePointer());
  }

 private:
  static void* TruePointer() { return reinterpret_cast<void*>(0x1); }
  static void* FalsePointer() { return NULL; }
  ThreadLocalPointer<void> tlp_;
  const bool default_value_;

  SB_DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
};

// An AllocationGroup is a collection of allocations that are logically lumped
// together, such as "Javascript" or "Graphics".
class AllocationGroup {
 public:
  explicit AllocationGroup(const std::string& name);
  ~AllocationGroup();
  const std::string& name() const { return name_; }

  void AddAllocation(int64_t num_bytes);
  void GetAggregateStats(int32_t* num_allocs, int64_t* allocation_bytes) const;

  int64_t allocation_bytes() const;
  int32_t num_allocations() const;

 private:
  const std::string name_;
  nb::atomic_int64_t allocation_bytes_;
  nb::atomic_int32_t num_allocations_;

  SB_DISALLOW_COPY_AND_ASSIGN(AllocationGroup);
};

// A self locking data structure that maps strings -> AllocationGroups. This is
// used to resolve MemoryGroup names (e.g. "Javascript") to an AllocationGroup
// which can be used to group allocations together.
class AtomicStringAllocationGroupMap {
 public:
  AtomicStringAllocationGroupMap();
  ~AtomicStringAllocationGroupMap();

  AllocationGroup* Ensure(const std::string& name);
  AllocationGroup* GetDefaultUnaccounted();

  bool Erase(const std::string& key);
  void GetAll(std::vector<const AllocationGroup*>* output) const;

 private:
  typedef std::map<std::string, AllocationGroup*> Map;
  Map group_map_;
  AllocationGroup* unaccounted_group_;
  mutable starboard::Mutex mutex_;

  SB_DISALLOW_COPY_AND_ASSIGN(AtomicStringAllocationGroupMap);
};

class AllocationGroupStack {
 public:
  AllocationGroupStack() { Push_DebugBreak(NULL); }
  ~AllocationGroupStack() {}

  void Push(AllocationGroup* group);
  void Pop();
  AllocationGroup* Peek();

  void Push_DebugBreak(AllocationGroup* ag) { debug_stack_.push_back(ag); }
  void Pop_DebugBreak() { debug_stack_.pop_back(); }
  AllocationGroup* Peek_DebugBreak() {
    if (debug_stack_.empty()) {
      return NULL;
    }
    return debug_stack_.back();
  }

 private:
  SB_DISALLOW_COPY_AND_ASSIGN(AllocationGroupStack);
  typedef std::vector<AllocationGroup*> AllocationGroupPtrVec;
  AllocationGroupPtrVec alloc_group_stack_, debug_stack_;
};

// A per-pointer map of allocations to AllocRecords. This map is thread safe.
class AtomicAllocationMap {
 public:
  AtomicAllocationMap();
  ~AtomicAllocationMap();

  // Returns true if Added. Otherwise false means that the pointer
  // already existed.
  bool Add(const void* memory, const AllocationRecord& alloc_record);

  // Returns true if the memory exists in this set.
  bool Get(const void* memory, AllocationRecord* alloc_record) const;

  // Return true if the memory existed in this set. If true
  // then output alloc_record is written with record that was found.
  // otherwise the record is written as 0 bytes and null key.
  bool Remove(const void* memory, AllocationRecord* alloc_record);

  bool Accept(AllocationVisitor* visitor) const;

  size_t Size() const;
  bool Empty() const;
  void Clear();

 private:
  SB_DISALLOW_COPY_AND_ASSIGN(AtomicAllocationMap);
  typedef std::map<const void*, AllocationRecord> PointerMap;

  PointerMap pointer_map_;
  mutable starboard::Mutex mutex_;
};

// A per-pointer map of allocations to AllocRecords. This is a hybrid data
// structure consisting of a hashtable of maps. Each pointer that is
// stored or retrieved is hashed to a random bucket. Each bucket has it's own
// lock. This distributed pattern increases performance significantly by
// reducing contention. The top-level hashtable is of constant size and does
// not resize. Each bucket is implemented as it's own map of elements.
class ConcurrentAllocationMap {
 public:
  static const int kNumElements = 511;
  ConcurrentAllocationMap();
  ~ConcurrentAllocationMap();

  // Returns true if Added. Otherwise false means that the pointer
  // already existed.
  bool Add(const void* memory, const AllocationRecord& alloc_record);
  // Returns true if the memory exists in this set.
  bool Get(const void* memory, AllocationRecord* alloc_record) const;
  // Return true if the memory existed in this set. If true
  // then output alloc_record is written with record that was found.
  // otherwise the record is written as 0 bytes and null key.
  bool Remove(const void* memory, AllocationRecord* alloc_record);
  size_t Size() const;
  bool Empty() const;
  void Clear();

  // Provides access to all the allocations within in a thread safe manner.
  bool Accept(AllocationVisitor* visitor) const;

  AtomicAllocationMap& GetMapForPointer(const void* ptr);
  const AtomicAllocationMap& GetMapForPointer(const void* ptr) const;

 private:
  SB_DISALLOW_COPY_AND_ASSIGN(ConcurrentAllocationMap);
  // Takes a pointer and generates a hash.
  static size_t hash_ptr(const void* ptr);

  int ToIndex(const void* ptr) const;
  AtomicAllocationMap pointer_map_array_[kNumElements];
};

}  // namespace analytics
}  // namespace nb

#endif  // NB_MEMORY_TRACKER_HELPERS_H_
