#ifndef _inlinevector_h_INCLUDED
#define _inlinevector_h_INCLUDED

#include "internal.h"

static inline unsigned *kissat_begin_vector (kissat *solver,
                                             vector *vector) {
#ifdef COMPACT
  return BEGIN_STACK (solver->vectors.stack) + vector->offset;
#else
  (void) solver;
  return vector->begin;
#endif
}

static inline unsigned *kissat_end_vector (kissat *solver, vector *vector) {
#ifdef COMPACT
  return kissat_begin_vector (solver, vector) + vector->size;
#else
  (void) solver;
  return vector->end;
#endif
}

static inline const unsigned *
kissat_begin_const_vector (kissat *solver, const vector *vector) {
#ifdef COMPACT
  return BEGIN_STACK (solver->vectors.stack) + vector->offset;
#else
  (void) solver;
  return vector->begin;
#endif
}

static inline const unsigned *
kissat_end_const_vector (kissat *solver, const vector *vector) {
#ifdef COMPACT
  return kissat_begin_const_vector (solver, vector) + vector->size;
#else
  (void) solver;
  return vector->end;
#endif
}

#if defined(LOGGING) || defined(TEST_VECTOR)

static inline size_t kissat_offset_vector (kissat *solver, vector *vector) {
#ifdef COMPACT
  (void) solver;
  return vector->offset;
#else
  unsigned *begin_vector = vector->begin;
  unsigned *begin_stack = BEGIN_STACK (solver->vectors.stack);
  return begin_vector ? begin_vector - begin_stack : 0;
#endif
}

#endif

static inline size_t kissat_size_vector (const vector *vector) {
#ifdef COMPACT
  return vector->size;
#else
  return vector->end - vector->begin;
#endif
}

static inline bool kissat_empty_vector (vector *vector) {
#ifdef COMPACT
  return !vector->size;
#else
  return vector->end == vector->begin;
#endif
}

static inline void kissat_inc_usable (kissat *solver) {
  assert (MAX_SECTOR > solver->vectors.usable);
  solver->vectors.usable++;
}

static inline void kissat_add_usable (kissat *solver, size_t inc) {
  assert (MAX_SECTOR - inc >= solver->vectors.usable);
  solver->vectors.usable += inc;
}

static inline unsigned *kissat_last_vector_pointer (kissat *solver,
                                                    vector *vector) {
  assert (!kissat_empty_vector (vector));
#ifdef COMPACT
  assert (vector->size);
  unsigned *begin = kissat_begin_vector (solver, vector);
  return begin + vector->size - 1;
#else
  (void) solver;
  return vector->end - 1;
#endif
}

#ifdef TEST_VECTOR

static inline void kissat_pop_vector (kissat *solver, vector *vector) {
  assert (!kissat_empty_vector (vector));
#ifdef COMPACT
  unsigned *p = kissat_last_vector_pointer (solver, vector);
  vector->size--;
  *p = INVALID_VECTOR_ELEMENT;
#else
  *--vector->end = INVALID_VECTOR_ELEMENT;
  (void) solver;
#endif
  kissat_inc_usable (solver);
}

#endif

static inline void kissat_release_vector (kissat *solver, vector *vector) {
  kissat_resize_vector (solver, vector, 0);
}

static inline void kissat_dec_usable (kissat *solver) {
  assert (solver->vectors.usable > 0);
  solver->vectors.usable--;
}

static inline void kissat_push_vectors (kissat *solver, vector *vector,
                                        unsigned e) {
  unsigneds *stack = &solver->vectors.stack;
  assert (e != INVALID_VECTOR_ELEMENT);
  if (
#ifdef COMPACT
      !vector->size && !vector->offset
#else
      !vector->begin
#endif
  ) {
    if (EMPTY_STACK (*stack))
      PUSH_STACK (*stack, 0);
    if (FULL_STACK (*stack)) {
      unsigned *end = kissat_enlarge_vector (solver, vector);
      assert (*end == INVALID_VECTOR_ELEMENT);
      *end = e;
      kissat_dec_usable (solver);
    } else {
#ifdef COMPACT
      assert ((uint64_t) SIZE_STACK (*stack) < MAX_VECTORS);
      vector->offset = SIZE_STACK (*stack);
      assert (vector->offset);
      *stack->end++ = e;
#else
      assert (stack->end < stack->allocated);
      *(vector->begin = stack->end++) = e;
#endif
    }
#if !defined(COMPACT)
    vector->end = vector->begin;
#endif
  } else {
    unsigned *end = kissat_end_vector (solver, vector);
    if (end == END_STACK (*stack)) {
      if (FULL_STACK (*stack)) {
        end = kissat_enlarge_vector (solver, vector);
        assert (*end == INVALID_VECTOR_ELEMENT);
        *end = e;
        kissat_dec_usable (solver);
      } else
        *stack->end++ = e;
    } else {
      if (*end != INVALID_VECTOR_ELEMENT)
        end = kissat_enlarge_vector (solver, vector);
      assert (*end == INVALID_VECTOR_ELEMENT);
      *end = e;
      kissat_dec_usable (solver);
    }
  }
#ifndef COMPACT
  vector->end++;
#else
  vector->size++;
#endif
  kissat_check_vectors (solver);
}

#ifdef TEST_VECTOR

#define all_vector(E, V) \
  unsigned E, *E##_PTR = kissat_begin_vector (solver, &V), \
              *const E##_END = kissat_end_vector (solver, &V); \
  E##_PTR != E##_END && (E = *E##_PTR, true); \
  E##_PTR++

#endif

#endif
