<commit_before>/*
 * Copyright (c) 2013 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/*
 * This test ensures that the PNaCl backends can deal with volatile
 * operations, C++11 atomic primitives and compiler intrinsics as would
 * be written by regular users, including PNaCl's ABI stabilization and
 * target lowering.
 *
 * This is a syntactical check as we do not run this multithreaded. Some
 * real testing is done here: tests/threads/thread_test.c
 *
 * PNaCl's atomic support is based on C11/C++11's, and also supports
 * GCC's legacy __sync_* intrinsics which internally map to the same IR
 * as C11/C++11's atomics. PNaCl only supports 8, 16, 32 and 64-bit
 * atomics, and should be able to handle any type that can map to these
 * (e.g. 32- and 64-bit atomic floating point load/store).
 */

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include "native_client/tests/toolchain/utils.h"

#define CONCAT_(A, B) A ## B
#define CONCAT(A, B) CONCAT_(A, B)
#define STR_(A) #A
#define STR(A) STR_(A)

#define CHECK_EQ(LHS, RHS, MSG) do {            \
    printf("\t" MSG ":\t" STR(LHS) "=%" PRIu64  \
           " and " STR(RHS) "=%" PRIu64 "\n",   \
           (uint64_t)(LHS), (uint64_t)(RHS));   \
    if ((LHS) != (RHS)) {                       \
      fprintf(stderr, "ERROR: " MSG ": `"       \
              STR(LHS) " != " STR(RHS) "` "     \
              "\n");                            \
      exit(1);                                  \
    }                                           \
  } while (0)

/*
 * GCC Legacy __sync Built-in Functions for Atomic Memory Access.
 * See:
 * http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/_005f_005fsync-Builtins.html
 *
 * Note: nand is ignored because it isn't in C11/C++11.
 */
void test_legacy_sync() {
  /*
   * fetch_and_*
   *
   * These built-in functions perform the operation suggested by the name,
   * and returns the value that had previously been in memory:
   *   { tmp = *ptr; *ptr op= value; return tmp; }
   *
   * *_and_fetch
   *
   * These built-in functions perform the operation suggested by the name,
   * and return the new value:
   *   { *ptr op= value; return *ptr; }
   */
# define FETCH_TEST(OPERATION_NAME, OPERATION, TYPE)  do {              \
    TYPE res, loc, value, res_, loc_, value_;                           \
    printf("Testing " STR(OPERATION_NAME) " with " STR(TYPE) "\n");     \
    /* Test __sync_fetch_and_* */                                       \
    loc = loc_ = 5;                                                     \
    value = value_ = 41;                                                \
    res = CONCAT(__sync_fetch_and_, OPERATION_NAME)(&loc, value);       \
    res_ = loc_; loc_ = loc_ OPERATION value_;                          \
    CHECK_EQ(res, res_, "__sync_fetch_and_" STR(OPERATION_NAME));       \
    /* Test __sync_*_and_fetch */                                       \
    loc = loc_ = 5;                                                     \
    value = value_ = 41;                                                \
    res = CONCAT(CONCAT(__sync_, OPERATION_NAME), _and_fetch)(          \
        &loc, value);                                                   \
    loc_ = loc_ OPERATION value_; res_ = loc_;                          \
    CHECK_EQ(res, res_, "__sync_" STR(OPERATION_NAME) "_and_fetch");    \
  } while (0)
# define FETCH_TEST_ALL_TYPES(OPERATION_NAME, OPERATION) do {   \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint8_t);             \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint16_t);            \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint32_t);            \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint64_t);            \
  } while (0)
  FETCH_TEST_ALL_TYPES(add, +);
  FETCH_TEST_ALL_TYPES(sub, -);
  FETCH_TEST_ALL_TYPES(or, |);
  FETCH_TEST_ALL_TYPES(and, &);
  FETCH_TEST_ALL_TYPES(xor, ^);

  /*
   * *_compare_and_swap
   *
   * These built-in functions perform an atomic compare and swap. That
   * is, if the current value of *ptr is oldval, then write newval into
   * *ptr. The “bool” version returns true if the comparison is
   * successful and newval is written. The "val" version returns the
   * contents of *ptr before the operation.
   *
   * Note: LLVM also has __sync_swap, which is ignored because it isn't
   * C11/C++11 and isn't in GCC.
   */
# define CAS_TEST(TYPE) do {                                    \
    TYPE res, loc, oldval, newval;                              \
    printf("Testing CAS with " STR(TYPE) "\n");                 \
    /* Test __sync_bool_compare_and_swap */                     \
    loc = 5;                                                    \
    oldval = 29;                                                \
    newval = 41;                                                \
    res = __sync_bool_compare_and_swap(&loc, oldval, newval);   \
    CHECK_EQ(res, 0, "__sync_bool_compare_and_swap");           \
    CHECK_EQ(loc, 5, "__sync_bool_compare_and_swap");           \
    loc = oldval;                                               \
    res = __sync_bool_compare_and_swap(&loc, oldval, newval);   \
    CHECK_EQ(res, 1, "__sync_bool_compare_and_swap");           \
    CHECK_EQ(loc, 41, "__sync_bool_compare_and_swap");          \
    /* Test __sync_val_compare_and_swap */                      \
    loc = 5;                                                    \
    oldval = 29;                                                \
    newval = 41;                                                \
    res = __sync_val_compare_and_swap(&loc, oldval, newval);    \
    CHECK_EQ(res, 5, "__sync_val_compare_and_swap");            \
    CHECK_EQ(loc, 5, "__sync_val_compare_and_swap");            \
    loc = oldval;                                               \
    res = __sync_val_compare_and_swap(&loc, oldval, newval);    \
    CHECK_EQ(res, oldval, "__sync_val_compare_and_swap");       \
    CHECK_EQ(loc, 41, "__sync_val_compare_and_swap");           \
  } while (0)
  CAS_TEST(uint8_t);
  CAS_TEST(uint16_t);
  CAS_TEST(uint32_t);
  CAS_TEST(uint64_t);

  /*
   * synchronize
   *
   * This built-in function issues a full memory barrier. Simply test
   * that it compiles fine.
   */
  __sync_synchronize();

  /*
   * lock_test_and_set
   *
   * This built-in function, as described by Intel, is not a traditional
   * test-and-set operation, but rather an atomic exchange operation. It
   * writes value into *ptr, and returns the previous contents of *ptr.
   * Many targets have only minimal support for such locks, and do not
   * support a full exchange operation. In this case, a target may
   * support reduced functionality here by which the only valid value to
   * store is the immediate constant 1. The exact value actually stored
   * in *ptr is implementation defined.
   *
   * This built-in function is not a full barrier, but rather an acquire
   * barrier. This means that references after the operation cannot move
   * to (or be speculated to) before the operation, but previous memory
   * stores may not be globally visible yet, and previous memory loads
   * may not yet be satisfied.
   *
   * lock_release
   *
   * This built-in function releases the lock acquired by
   * __sync_lock_test_and_set. Normally this means writing the constant
   * 0 to *ptr.
   *
   * This built-in function is not a full barrier, but rather a release
   * barrier. This means that all previous memory stores are globally
   * visible, and all previous memory loads have been satisfied, but
   * following memory reads are not prevented from being speculated to
   * before the barrier.
   */
# define TAS_TEST(TYPE) do {                            \
    TYPE res, loc, value;                               \
    printf("Testing TAS with " STR(TYPE) "\n");         \
    loc = 5;                                            \
    value = 41;                                         \
    res = __sync_lock_test_and_set(&loc, value);        \
    CHECK_EQ(res, 5, "__sync_lock_test_and_set");       \
    CHECK_EQ(loc, 41, "__sync_lock_test_and_set");      \
    __sync_lock_release(&loc);                          \
    CHECK_EQ(loc, 0,  "__sync_lock_release");           \
  } while (0)
  TAS_TEST(uint8_t);
  TAS_TEST(uint16_t);
  TAS_TEST(uint32_t);
  TAS_TEST(uint64_t);
}

void test_volatile() {
# define VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, TYPE) do {  \
    volatile TYPE loc = 5;                                              \
    TYPE loc_ = 5;                                                      \
    TYPE value = 41;                                                    \
    printf("Testing volatile " STR(OPERATION_NAME)                      \
           " with " STR(TYPE) "\n");                                    \
    loc = loc OPERATION value;                                          \
    loc_ = loc_ OPERATION value;                                        \
    CHECK_EQ(loc, loc_, "volatile " STR(TYPE) " " STR(OPERATION_NAME)); \
  } while (0)
# define VOLATILE_OPERATION_TEST_ALL_TYPES(OPERATION_NAME, OPERATION)   \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint8_t);          \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint16_t);         \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint32_t);         \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint64_t);
# define VOLATILE_LOAD_STORE_TEST(TYPE) do {            \
    volatile TYPE loc = 5;                              \
    TYPE res = loc;                                     \
    CHECK_EQ(res, 5, "volatile " STR(TYPE) " load");    \
    loc = 41;                                           \
    CHECK_EQ(loc, 41, "volatile " STR(TYPE) " store");  \
  } while (0)
  VOLATILE_OPERATION_TEST_ALL_TYPES(add, +);
  VOLATILE_OPERATION_TEST_ALL_TYPES(sub, -);
  VOLATILE_OPERATION_TEST_ALL_TYPES(or,  |);
  VOLATILE_OPERATION_TEST_ALL_TYPES(and, &);
  VOLATILE_OPERATION_TEST_ALL_TYPES(xor, ^);
  VOLATILE_LOAD_STORE_TEST(uint8_t);
  VOLATILE_LOAD_STORE_TEST(uint16_t);
  VOLATILE_LOAD_STORE_TEST(uint32_t);
  VOLATILE_LOAD_STORE_TEST(uint64_t);
  VOLATILE_LOAD_STORE_TEST(float);
  VOLATILE_LOAD_STORE_TEST(double);
}

void test_cpp11_atomic() {
  // TODO(jfb) Test C++11 atomic features.
  //   - ATOMIC_*_LOCK_FREE
  //   - std::atomic and their functions (including is_lock_free).
  //   - std::atomic_flag.
  //   - std::atomic_thread_fence (atomic_signal_fence currently unsupported).
  //   - 6 memory orders.
}

int main() {
  test_legacy_sync();
  test_volatile();
  test_cpp11_atomic();
  return 0;
}
<commit_msg>Test no-read uses of synchronization primitives<commit_after>/*
 * Copyright (c) 2013 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/*
 * This test ensures that the PNaCl backends can deal with volatile
 * operations, C++11 atomic primitives and compiler intrinsics as would
 * be written by regular users, including PNaCl's ABI stabilization and
 * target lowering.
 *
 * This is a syntactical check as we do not run this multithreaded. Some
 * real testing is done here: tests/threads/thread_test.c
 *
 * PNaCl's atomic support is based on C11/C++11's, and also supports
 * GCC's legacy __sync_* intrinsics which internally map to the same IR
 * as C11/C++11's atomics. PNaCl only supports 8, 16, 32 and 64-bit
 * atomics, and should be able to handle any type that can map to these
 * (e.g. 32- and 64-bit atomic floating point load/store).
 */

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include "native_client/tests/toolchain/utils.h"

#define CONCAT_(A, B) A ## B
#define CONCAT(A, B) CONCAT_(A, B)
#define STR_(A) #A
#define STR(A) STR_(A)

#define CHECK_EQ(LHS, RHS, MSG) do {            \
    printf("\t" MSG ":\t" STR(LHS) "=%" PRIu64  \
           " and " STR(RHS) "=%" PRIu64 "\n",   \
           (uint64_t)(LHS), (uint64_t)(RHS));   \
    if ((LHS) != (RHS)) {                       \
      fprintf(stderr, "ERROR: " MSG ": `"       \
              STR(LHS) " != " STR(RHS) "` "     \
              "\n");                            \
      exit(1);                                  \
    }                                           \
  } while (0)

// Test that using some synchronization primitives without using the
// return value works. Do this by modifying volatile globals.
volatile uint8_t g_uint8_t = 0;
volatile uint16_t g_uint16_t = 0;
volatile uint32_t g_uint32_t = 0;
volatile uint64_t g_uint64_t = 0;
#define SINK_ADDR(TYPE) (&CONCAT(g_, TYPE))

// Test that base+displacement as synchronization address also works,
// with small and big displacements (which should affect unrolling).
//
// Small displacement.
static const size_t gsmall_ArrSize = 8;
volatile struct GS8 { void *ptr; uint8_t arr[gsmall_ArrSize]; }
  gsmall_uint8_t = { 0, { 0 } };
volatile struct GS16 { void *ptr; uint16_t arr[gsmall_ArrSize]; }
  gsmall_uint16_t = { 0, { 0 } };
volatile struct GS32 { void *ptr; uint32_t arr[gsmall_ArrSize]; }
  gsmall_uint32_t = { 0, { 0 } };
volatile struct GS64 { void *ptr; uint64_t arr[gsmall_ArrSize]; }
  gsmall_uint64_t = { 0, { 0 } };
#define SMALL_SINK_ADDR(TYPE) (                                         \
    CONCAT(gsmall_, TYPE).ptr = (void*) CONCAT(gsmall_, TYPE).arr,      \
    (TYPE*) CONCAT(gsmall_, TYPE).ptr)
// Big displacement.
static const size_t gbig_ArrSize = 128;
volatile struct GB8 { void *ptr; uint8_t arr[gbig_ArrSize]; }
  gbig_uint8_t = { 0, { 0 } };
volatile struct GB16 { void *ptr; uint16_t arr[gbig_ArrSize]; }
  gbig_uint16_t = { 0, { 0 } };
volatile struct GB32 { void *ptr; uint32_t arr[gbig_ArrSize]; }
  gbig_uint32_t = { 0, { 0 } };
volatile struct GB64 { void *ptr; uint64_t arr[gbig_ArrSize]; }
  gbig_uint64_t = { 0, { 0 } };
#define BIG_SINK_ADDR(TYPE) (                                   \
    CONCAT(gbig_, TYPE).ptr = (void*) CONCAT(gbig_, TYPE).arr,  \
    (TYPE*) CONCAT(gbig_, TYPE).ptr)

/*
 * GCC Legacy __sync Built-in Functions for Atomic Memory Access.
 * See:
 * http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/_005f_005fsync-Builtins.html
 *
 * Note: nand is ignored because it isn't in C11/C++11.
 */
void test_legacy_sync() {
  /*
   * fetch_and_*
   *
   * These built-in functions perform the operation suggested by the name,
   * and returns the value that had previously been in memory:
   *   { tmp = *ptr; *ptr op= value; return tmp; }
   *
   * *_and_fetch
   *
   * These built-in functions perform the operation suggested by the name,
   * and return the new value:
   *   { *ptr op= value; return *ptr; }
   */
# define FETCH_TEST(OPERATION_NAME, OPERATION, TYPE)  do {              \
    TYPE res, loc, value, res_, loc_, value_;                           \
    printf("Testing " STR(OPERATION_NAME) " with " STR(TYPE) "\n");     \
    /* Test __sync_fetch_and_* */                                       \
    loc = loc_ = 5;                                                     \
    value = value_ = 41;                                                \
    res = CONCAT(__sync_fetch_and_, OPERATION_NAME)(&loc, value);       \
    res_ = loc_; loc_ = loc_ OPERATION value_;                          \
    CHECK_EQ(res, res_, "__sync_fetch_and_" STR(OPERATION_NAME));       \
    /* Test __sync_*_and_fetch */                                       \
    loc = loc_ = 5;                                                     \
    value = value_ = 41;                                                \
    res = CONCAT(CONCAT(__sync_, OPERATION_NAME), _and_fetch)(          \
        &loc, value);                                                   \
    loc_ = loc_ OPERATION value_; res_ = loc_;                          \
    CHECK_EQ(res, res_, "__sync_" STR(OPERATION_NAME) "_and_fetch");    \
    /* Test the above two variants, without reading the result back. */ \
    { /* In just one variable. */                                       \
      volatile TYPE *sink = SINK_ADDR(TYPE);                            \
      (void) CONCAT(__sync_fetch_and_, OPERATION_NAME)(sink, value);    \
      (void) CONCAT(CONCAT(__sync_, OPERATION_NAME), _and_fetch)(       \
          sink, value);                                                 \
    }                                                                   \
    { /* In a small array. */                                           \
      volatile TYPE *small_sink = SMALL_SINK_ADDR(TYPE);                \
      for (size_t i = 0; i != gsmall_ArrSize; ++i) {                    \
        (void) CONCAT(__sync_fetch_and_, OPERATION_NAME)(               \
            &small_sink[i], value);                                     \
        (void) CONCAT(CONCAT(__sync_, OPERATION_NAME), _and_fetch)(     \
            &small_sink[i], value);                                     \
      }                                                                 \
    }                                                                   \
    { /* In a big array. */                                             \
      volatile TYPE *big_sink = BIG_SINK_ADDR(TYPE);                    \
      for (size_t i = 0; i != gbig_ArrSize; ++i) {                      \
        (void) CONCAT(__sync_fetch_and_, OPERATION_NAME)(               \
            &big_sink[i], value);                                       \
        (void) CONCAT(CONCAT(__sync_, OPERATION_NAME), _and_fetch)(     \
            &big_sink[i], value);                                       \
      }                                                                 \
    }                                                                   \
  } while (0)
# define FETCH_TEST_ALL_TYPES(OPERATION_NAME, OPERATION) do {   \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint8_t);             \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint16_t);            \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint32_t);            \
    FETCH_TEST(OPERATION_NAME, OPERATION, uint64_t);            \
  } while (0)
  FETCH_TEST_ALL_TYPES(add, +);
  FETCH_TEST_ALL_TYPES(sub, -);
  FETCH_TEST_ALL_TYPES(or, |);
  FETCH_TEST_ALL_TYPES(and, &);
  FETCH_TEST_ALL_TYPES(xor, ^);

  /*
   * *_compare_and_swap
   *
   * These built-in functions perform an atomic compare and swap. That
   * is, if the current value of *ptr is oldval, then write newval into
   * *ptr. The “bool” version returns true if the comparison is
   * successful and newval is written. The "val" version returns the
   * contents of *ptr before the operation.
   *
   * Note: LLVM also has __sync_swap, which is ignored because it isn't
   * C11/C++11 and isn't in GCC.
   */
# define CAS_TEST(TYPE) do {                                            \
    TYPE res, loc, oldval, newval;                                      \
    printf("Testing CAS with " STR(TYPE) "\n");                         \
    /* Test __sync_bool_compare_and_swap */                             \
    loc = 5;                                                            \
    oldval = 29;                                                        \
    newval = 41;                                                        \
    res = __sync_bool_compare_and_swap(&loc, oldval, newval);           \
    CHECK_EQ(res, 0, "__sync_bool_compare_and_swap");                   \
    CHECK_EQ(loc, 5, "__sync_bool_compare_and_swap");                   \
    loc = oldval;                                                       \
    res = __sync_bool_compare_and_swap(&loc, oldval, newval);           \
    CHECK_EQ(res, 1, "__sync_bool_compare_and_swap");                   \
    CHECK_EQ(loc, 41, "__sync_bool_compare_and_swap");                  \
    /* Test __sync_val_compare_and_swap */                              \
    loc = 5;                                                            \
    oldval = 29;                                                        \
    newval = 41;                                                        \
    res = __sync_val_compare_and_swap(&loc, oldval, newval);            \
    CHECK_EQ(res, 5, "__sync_val_compare_and_swap");                    \
    CHECK_EQ(loc, 5, "__sync_val_compare_and_swap");                    \
    loc = oldval;                                                       \
    res = __sync_val_compare_and_swap(&loc, oldval, newval);            \
    CHECK_EQ(res, oldval, "__sync_val_compare_and_swap");               \
    CHECK_EQ(loc, 41, "__sync_val_compare_and_swap");                   \
    /* Test the above two variants, without reading the result back. */ \
    { /* In just one variable. */                                       \
      volatile TYPE *sink = SINK_ADDR(TYPE);                            \
      (void) __sync_bool_compare_and_swap(sink, oldval, newval);        \
      (void) __sync_val_compare_and_swap(sink, oldval, newval);         \
    }                                                                   \
    { /* In a small array. */                                           \
      volatile TYPE *small_sink = SMALL_SINK_ADDR(TYPE);                \
      for (size_t i = 0; i != gsmall_ArrSize; ++i) {                    \
        (void) __sync_bool_compare_and_swap(                            \
            &small_sink[i], oldval, newval);                            \
        (void) __sync_val_compare_and_swap(                             \
            &small_sink[i], oldval, newval);                            \
      }                                                                 \
    }                                                                   \
    { /* In a big array. */                                             \
      volatile TYPE *big_sink = BIG_SINK_ADDR(TYPE);                    \
      for (size_t i = 0; i != gbig_ArrSize; ++i) {                      \
        (void) __sync_bool_compare_and_swap(                            \
            &big_sink[i], oldval, newval);                              \
        (void) __sync_val_compare_and_swap(                             \
            &big_sink[i], oldval, newval);                              \
      }                                                                 \
    }                                                                   \
  } while (0)
  CAS_TEST(uint8_t);
  CAS_TEST(uint16_t);
  CAS_TEST(uint32_t);
  CAS_TEST(uint64_t);

  /*
   * synchronize
   *
   * This built-in function issues a full memory barrier. Simply test
   * that it compiles fine.
   */
  __sync_synchronize();

  /*
   * lock_test_and_set
   *
   * This built-in function, as described by Intel, is not a traditional
   * test-and-set operation, but rather an atomic exchange operation. It
   * writes value into *ptr, and returns the previous contents of *ptr.
   * Many targets have only minimal support for such locks, and do not
   * support a full exchange operation. In this case, a target may
   * support reduced functionality here by which the only valid value to
   * store is the immediate constant 1. The exact value actually stored
   * in *ptr is implementation defined.
   *
   * This built-in function is not a full barrier, but rather an acquire
   * barrier. This means that references after the operation cannot move
   * to (or be speculated to) before the operation, but previous memory
   * stores may not be globally visible yet, and previous memory loads
   * may not yet be satisfied.
   *
   * lock_release
   *
   * This built-in function releases the lock acquired by
   * __sync_lock_test_and_set. Normally this means writing the constant
   * 0 to *ptr.
   *
   * This built-in function is not a full barrier, but rather a release
   * barrier. This means that all previous memory stores are globally
   * visible, and all previous memory loads have been satisfied, but
   * following memory reads are not prevented from being speculated to
   * before the barrier.
   */
# define TAS_TEST(TYPE) do {                                            \
    TYPE res, loc, value;                                               \
    printf("Testing TAS with " STR(TYPE) "\n");                         \
    /* Test __sync_lock_test_and_set. */                                \
    loc = 5;                                                            \
    value = 41;                                                         \
    res = __sync_lock_test_and_set(&loc, value);                        \
    CHECK_EQ(res, 5, "__sync_lock_test_and_set");                       \
    CHECK_EQ(loc, 41, "__sync_lock_test_and_set");                      \
    /* Test __sync_lock_release. */                                     \
    __sync_lock_release(&loc);                                          \
    CHECK_EQ(loc, 0,  "__sync_lock_release");                           \
    { /* In just one variable. */                                       \
      volatile TYPE *sink = SINK_ADDR(TYPE);                            \
      (void) __sync_lock_test_and_set(sink, value);                     \
      __sync_lock_release(sink);                                        \
    }                                                                   \
    /* Test the above two variants, without reading the result back. */ \
    { /* In a small array. */                                           \
      volatile TYPE *small_sink = SMALL_SINK_ADDR(TYPE);                \
      for (size_t i = 0; i != gsmall_ArrSize; ++i) {                    \
        (void) __sync_lock_test_and_set(&small_sink[i], value);         \
        __sync_lock_release(&small_sink[i]);                            \
      }                                                                 \
    }                                                                   \
    { /* In a big array. */                                             \
      volatile TYPE *big_sink = BIG_SINK_ADDR(TYPE);                    \
      for (size_t i = 0; i != gbig_ArrSize; ++i) {                      \
        (void) __sync_lock_test_and_set(&big_sink[i], value);           \
        __sync_lock_release(&big_sink[i]);                              \
      }                                                                 \
    }                                                                   \
  } while (0)
  TAS_TEST(uint8_t);
  TAS_TEST(uint16_t);
  TAS_TEST(uint32_t);
  TAS_TEST(uint64_t);
}

void test_volatile() {
# define VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, TYPE) do {  \
    volatile TYPE loc = 5;                                              \
    TYPE loc_ = 5;                                                      \
    TYPE value = 41;                                                    \
    printf("Testing volatile " STR(OPERATION_NAME)                      \
           " with " STR(TYPE) "\n");                                    \
    loc = loc OPERATION value;                                          \
    loc_ = loc_ OPERATION value;                                        \
    CHECK_EQ(loc, loc_, "volatile " STR(TYPE) " " STR(OPERATION_NAME)); \
  } while (0)
# define VOLATILE_OPERATION_TEST_ALL_TYPES(OPERATION_NAME, OPERATION)   \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint8_t);          \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint16_t);         \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint32_t);         \
  VOLATILE_OPERATION_TEST(OPERATION_NAME, OPERATION, uint64_t);
# define VOLATILE_LOAD_STORE_TEST(TYPE) do {            \
    volatile TYPE loc = 5;                              \
    TYPE res = loc;                                     \
    CHECK_EQ(res, 5, "volatile " STR(TYPE) " load");    \
    loc = 41;                                           \
    CHECK_EQ(loc, 41, "volatile " STR(TYPE) " store");  \
  } while (0)
  VOLATILE_OPERATION_TEST_ALL_TYPES(add, +);
  VOLATILE_OPERATION_TEST_ALL_TYPES(sub, -);
  VOLATILE_OPERATION_TEST_ALL_TYPES(or,  |);
  VOLATILE_OPERATION_TEST_ALL_TYPES(and, &);
  VOLATILE_OPERATION_TEST_ALL_TYPES(xor, ^);
  VOLATILE_LOAD_STORE_TEST(uint8_t);
  VOLATILE_LOAD_STORE_TEST(uint16_t);
  VOLATILE_LOAD_STORE_TEST(uint32_t);
  VOLATILE_LOAD_STORE_TEST(uint64_t);
  VOLATILE_LOAD_STORE_TEST(float);
  VOLATILE_LOAD_STORE_TEST(double);
}

void test_cpp11_atomic() {
  // TODO(jfb) Test C++11 atomic features.
  //   - ATOMIC_*_LOCK_FREE
  //   - std::atomic and their functions (including is_lock_free).
  //   - std::atomic_flag.
  //   - std::atomic_thread_fence (atomic_signal_fence currently unsupported).
  //   - 6 memory orders.
}

int main() {
  test_legacy_sync();
  test_volatile();
  test_cpp11_atomic();
  return 0;
}
<|endoftext|>


<commit_before>#include <exception>
#include <iostream>
#include <memory>
#include <mpi.h>
#include <random>
#include <functional>
#include <sstream>
#include <string>
#include <typeinfo>
#include <vector>
#include <ctime>

#include "BenchmarkRunner.h"
#include "Configuration.h"
#include "matrix/smp/SMPMatrixElf.h"
#include "matrix/MatrixHelper.h"
#include "matrix/Matrix.h"

using namespace std;

void generateProblemData(stringstream& in, stringstream& out)
{
    Matrix<float> first(100,100);
    Matrix<float> second(100, 100);
    auto distribution = uniform_real_distribution<float> (-100, +100);
    auto engine = mt19937(time(nullptr));
    auto generator = bind(distribution, engine);
    MatrixHelper::fill(first, generator);
    MatrixHelper::fill(second, generator);
    MatrixHelper::writeMatrixTo(in, first);
    MatrixHelper::writeMatrixTo(in, second);
}

int main(int argc, char** argv)
{
    Configuration config(argc, argv);
    MPI::Init(argc, argv);

    try
    {
    	unique_ptr<ElfFactory> factory(config.getElfFactory());
        stringstream in;
        stringstream out;

        generateProblemData(in, out);
        ProblemStatement statement{ in, out, "matrix"};

        BenchmarkRunner runner(100);
        runner.runBenchmark(statement, *factory);
        auto results = runner.getResults();
        for (const auto& result: results)
        {
            cout << result.first << " - " <<result.second<<endl;
        }
    }
    catch (exception &e)
    {
        cerr << "FATAL: " << e.what() << endl;
        return 1;
    }
    catch (...)
    {
        cerr << "FATAL ERROR of unknown type." << endl;
        return 1;
    }

    MPI::Finalize();
    return 0;
}

<commit_msg>Tabs to spaces...<commit_after>#include <exception>
#include <iostream>
#include <memory>
#include <mpi.h>
#include <random>
#include <functional>
#include <sstream>
#include <string>
#include <typeinfo>
#include <vector>
#include <ctime>

#include "BenchmarkRunner.h"
#include "Configuration.h"
#include "matrix/smp/SMPMatrixElf.h"
#include "matrix/MatrixHelper.h"
#include "matrix/Matrix.h"

using namespace std;

void generateProblemData(stringstream& in, stringstream& out)
{
    Matrix<float> first(100,100);
    Matrix<float> second(100, 100);
    auto distribution = uniform_real_distribution<float> (-100, +100);
    auto engine = mt19937(time(nullptr));
    auto generator = bind(distribution, engine);
    MatrixHelper::fill(first, generator);
    MatrixHelper::fill(second, generator);
    MatrixHelper::writeMatrixTo(in, first);
    MatrixHelper::writeMatrixTo(in, second);
}

int main(int argc, char** argv)
{
    Configuration config(argc, argv);
    MPI::Init(argc, argv);

    try
    {
        unique_ptr<ElfFactory> factory(config.getElfFactory());
        stringstream in;
        stringstream out;

        generateProblemData(in, out);
        ProblemStatement statement{ in, out, "matrix"};

        BenchmarkRunner runner(100);
        runner.runBenchmark(statement, *factory);
        auto results = runner.getResults();
        for (const auto& result: results)
        {
            cout << result.first << " - " <<result.second<<endl;
        }
    }
    catch (exception &e)
    {
        cerr << "FATAL: " << e.what() << endl;
        return 1;
    }
    catch (...)
    {
        cerr << "FATAL ERROR of unknown type." << endl;
        return 1;
    }

    MPI::Finalize();
    return 0;
}

<|endoftext|>


<commit_before>/*
 * Unit tests for the TTValue object
 * Copyright © 2011, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTValueTest.h"

#define thisTTClass			TTValueTest
#define thisTTClassName		"value.test"
#define thisTTClassTags		"test, foundation"

TT_OBJECT_CONSTRUCTOR
{;}

TTValueTest::~TTValueTest()
{;}

void TTValueTestBasic(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing basic TTValue operation");

	TTValue v1(3.14);

	TTTestAssertion("init with a double is correctly typed as kTypeFloat64",
					v1.getType(0) == kTypeFloat64,
					testAssertionCount,
					errorCount);

	TTTestAssertion("init with a double has correct element count",
					v1.getSize() == 1,
					testAssertionCount,
					errorCount);

	TTTestAssertion("init with a double has correct value when retrieved as a double",
					TTTestFloatEquivalence(double(v1), 3.14),
					testAssertionCount,
					errorCount);

	TTTestAssertion("init with a double has correct value when retrieved as an TTInt32",
					TTInt32(v1) == 3,
					testAssertionCount,
					errorCount);

	TTTestLog("Appending a symbol to TTValue");
	v1.append(TT("foo"));

	TTTestAssertion("TTValue correctly updated element count to 2",
					v1.getSize() == 2,
					testAssertionCount,
					errorCount);

	TTTestAssertion("first item still is correctly typed as kTypeFloat64",
					v1.getType(0) == kTypeFloat64,
					testAssertionCount,
					errorCount);

	TTTestAssertion("first item still has correct value when retrieved as a double",
					TTTestFloatEquivalence(double(v1), 3.14),
					testAssertionCount,
					errorCount);

	TTTestAssertion("second item has correct type",
					v1.getType(1) == kTypeSymbol,
					testAssertionCount,
					errorCount);

	// TODO: want to implement this:
	// TTSymbolPtr s = v1[1];
	TTSymbolPtr s = NULL;
	v1.get(1, &s);
	TTTestAssertion("second item has correct value, retreiving with get() method",
					s == TT("foo"),
					testAssertionCount,
					errorCount);

	TTTestLog("Clearing TTValue");
	v1.clear();

	TTTestAssertion("element count is zero",
					v1.getSize() == 0,
					testAssertionCount,
					errorCount);

	TTTestAssertion("type of TTValue which is returned is kTypeNone",
					v1.getType() == kTypeNone,
					testAssertionCount,
					errorCount);

}

void TTValueTestStringConversion(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing TTValue string conversion methods");

	// TODO: test toString()
	// TODO: test fromString()
	// TODO: test transformCSVStringToSymbolArray()

	TTValue v1(3.14);
}

void TTValueTestNumericTransformations(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing TTValue numeric transformations");

	/****************************************************************************************************/
	TTTestLog("\n");
	TTTestLog("Testing clip()");
	/****************************************************************************************************/

	// TTFloat64

	TTValue v1(3.14);

	v1.clip(6.0, 12.0);
	TTTestAssertion("positive double clipped (out of lower bound)",
					TTTestFloatEquivalence(double(v1), 6.0),
					testAssertionCount,
					errorCount);

	v1 = 3.14;
	v1.clip(0.0, 4.0);
	TTTestAssertion("positive double not clipped (within range)",
					TTTestFloatEquivalence(double(v1), 3.14),
					testAssertionCount,
					errorCount);

	v1 = 3.14;
	v1.clip(0.0, 2.0);
	TTTestAssertion("positive double clipped (out of upper bound)",
					TTTestFloatEquivalence(double(v1), 2.0),
					testAssertionCount,
					errorCount);

	v1 = -3.14;
	v1.clip(-2.0, 0.0);
	TTTestAssertion("negative double clipped (out of lower bound)",
					TTTestFloatEquivalence(double(v1), -2.0),
					testAssertionCount,
					errorCount);

	v1 = -3.14;
	v1.clip(-4.0, 0.0);
	TTTestAssertion("negative double not clipped (within range)",
					TTTestFloatEquivalence(double(v1), -3.14),
					testAssertionCount,
					errorCount);

	v1 = -3.14;
	v1.clip(-8.0, -4.0);
	TTTestAssertion("negative double clipped (out of upper bound)",
					TTTestFloatEquivalence(double(v1), -4.0),
					testAssertionCount,
					errorCount);

	// TTInt8

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt8 clipped (out of lower bound)",
					TTInt8(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt8 not clipped (within range)",
					TTInt8(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt8 clipped (out of upper bound)",
					TTInt8(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt8 clipped (out of lower bound)",
					TTInt8(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt8 not clipped (within range)",
					TTInt8(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt8 clipped (out of upper bound)",
					TTInt8(v1) == -4,
					testAssertionCount,
					errorCount);

	// TTInt16

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt16 clipped (out of lower bound)",
					TTInt16(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt16 not clipped (within range)",
					TTInt16(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt16 clipped (out of upper bound)",
					TTInt16(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt16 clipped (out of lower bound)",
					TTInt16(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt16 not clipped (within range)",
					TTInt16(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt16 clipped (out of upper bound)",
					TTInt16(v1) == -4,
					testAssertionCount,
					errorCount);

	// TTInt32

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt32 clipped (out of lower bound)",
					TTInt32(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt32 not clipped (within range)",
					TTInt32(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt32 clipped (out of upper bound)",
					TTInt32(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt32 clipped (out of lower bound)",
					TTInt32(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt32 not clipped (within range)",
					TTInt32(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt32 clipped (out of upper bound)",
					TTInt32(v1) == -4,
					testAssertionCount,
					errorCount);

	// TTInt64

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt64 clipped (out of lower bound)",
					TTInt64(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt64 not clipped (within range)",
					TTInt64(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt64 clipped (out of upper bound)",
					TTInt64(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt64 clipped (out of lower bound)",
					TTInt64(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt64 not clipped (within range)",
					TTInt64(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt64 clipped (out of upper bound)",
					TTInt64(v1) == -4,
					testAssertionCount,
					errorCount);

	// TODO: test cliplow()
	// TODO: test cliphigh()
	// TODO: test round()
	// TODO: test truncate()
	// TODO: test booleanize()

	//TTValue v1(3.14);
}

void TTValueTestOperators(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing TTValue operators");

	// TODO: test >
	// TODO: test ==
	// TODO: test =
	// TODO: test casting
	// TODO: should + be concatenating elements to create a new value of a+b element count?

	TTValue v1(3.14);
}

// TODO: Benchmarking

TTErr TTValueTest::test(TTValue& returnedTestInfo)
{
	int	errorCount = 0;
	int testAssertionCount = 0;

	TTValueTestBasic(errorCount, testAssertionCount);
	TTValueTestStringConversion(errorCount, testAssertionCount);
	TTValueTestNumericTransformations(errorCount, testAssertionCount);
	TTValueTestOperators(errorCount, testAssertionCount);

	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}
<commit_msg>Adding clip tests for Unsigned 8/16/32/64 bits ints<commit_after>/*
 * Unit tests for the TTValue object
 * Copyright © 2011, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTValueTest.h"

#define thisTTClass			TTValueTest
#define thisTTClassName		"value.test"
#define thisTTClassTags		"test, foundation"

TT_OBJECT_CONSTRUCTOR
{;}

TTValueTest::~TTValueTest()
{;}

void TTValueTestBasic(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing basic TTValue operation");

	TTValue v1(3.14);

	TTTestAssertion("init with a double is correctly typed as kTypeFloat64",
					v1.getType(0) == kTypeFloat64,
					testAssertionCount,
					errorCount);

	TTTestAssertion("init with a double has correct element count",
					v1.getSize() == 1,
					testAssertionCount,
					errorCount);

	TTTestAssertion("init with a double has correct value when retrieved as a double",
					TTTestFloatEquivalence(double(v1), 3.14),
					testAssertionCount,
					errorCount);

	TTTestAssertion("init with a double has correct value when retrieved as an TTInt32",
					TTInt32(v1) == 3,
					testAssertionCount,
					errorCount);

	TTTestLog("Appending a symbol to TTValue");
	v1.append(TT("foo"));

	TTTestAssertion("TTValue correctly updated element count to 2",
					v1.getSize() == 2,
					testAssertionCount,
					errorCount);

	TTTestAssertion("first item still is correctly typed as kTypeFloat64",
					v1.getType(0) == kTypeFloat64,
					testAssertionCount,
					errorCount);

	TTTestAssertion("first item still has correct value when retrieved as a double",
					TTTestFloatEquivalence(double(v1), 3.14),
					testAssertionCount,
					errorCount);

	TTTestAssertion("second item has correct type",
					v1.getType(1) == kTypeSymbol,
					testAssertionCount,
					errorCount);

	// TODO: want to implement this:
	// TTSymbolPtr s = v1[1];
	TTSymbolPtr s = NULL;
	v1.get(1, &s);
	TTTestAssertion("second item has correct value, retreiving with get() method",
					s == TT("foo"),
					testAssertionCount,
					errorCount);

	TTTestLog("Clearing TTValue");
	v1.clear();

	TTTestAssertion("element count is zero",
					v1.getSize() == 0,
					testAssertionCount,
					errorCount);

	TTTestAssertion("type of TTValue which is returned is kTypeNone",
					v1.getType() == kTypeNone,
					testAssertionCount,
					errorCount);

}

void TTValueTestStringConversion(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing TTValue string conversion methods");

	// TODO: test toString()
	// TODO: test fromString()
	// TODO: test transformCSVStringToSymbolArray()

	TTValue v1(3.14);
}

void TTValueTestNumericTransformations(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing TTValue numeric transformations");

	/****************************************************************************************************/
	TTTestLog("\n");
	TTTestLog("Testing clip()");
	/****************************************************************************************************/

	// TTFloat64

	TTValue v1(3.14);

	v1.clip(6.0, 12.0);
	TTTestAssertion("positive double clipped (out of lower bound)",
					TTTestFloatEquivalence(double(v1), 6.0),
					testAssertionCount,
					errorCount);

	v1 = 3.14;
	v1.clip(0.0, 4.0);
	TTTestAssertion("positive double not clipped (within range)",
					TTTestFloatEquivalence(double(v1), 3.14),
					testAssertionCount,
					errorCount);

	v1 = 3.14;
	v1.clip(0.0, 2.0);
	TTTestAssertion("positive double clipped (out of upper bound)",
					TTTestFloatEquivalence(double(v1), 2.0),
					testAssertionCount,
					errorCount);

	v1 = -3.14;
	v1.clip(-2.0, 0.0);
	TTTestAssertion("negative double clipped (out of lower bound)",
					TTTestFloatEquivalence(double(v1), -2.0),
					testAssertionCount,
					errorCount);

	v1 = -3.14;
	v1.clip(-4.0, 0.0);
	TTTestAssertion("negative double not clipped (within range)",
					TTTestFloatEquivalence(double(v1), -3.14),
					testAssertionCount,
					errorCount);

	v1 = -3.14;
	v1.clip(-8.0, -4.0);
	TTTestAssertion("negative double clipped (out of upper bound)",
					TTTestFloatEquivalence(double(v1), -4.0),
					testAssertionCount,
					errorCount);

	// TTInt8

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt8 clipped (out of lower bound)",
					TTInt8(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt8 not clipped (within range)",
					TTInt8(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt8 clipped (out of upper bound)",
					TTInt8(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt8 clipped (out of lower bound)",
					TTInt8(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt8 not clipped (within range)",
					TTInt8(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt8(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt8 clipped (out of upper bound)",
					TTInt8(v1) == -4,
					testAssertionCount,
					errorCount);

	// TTUInt8

	v1.clip(6, 12);
	TTTestAssertion("positive TTUInt8 clipped (out of lower bound)",
					TTUInt8(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTUInt8(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTUInt8 not clipped (within range)",
					TTUInt8(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTUInt8(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTUInt8 clipped (out of upper bound)",
					TTUInt8(v1) == 2,
					testAssertionCount,
					errorCount);

	// TTInt16

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt16 clipped (out of lower bound)",
					TTInt16(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt16 not clipped (within range)",
					TTInt16(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt16 clipped (out of upper bound)",
					TTInt16(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt16 clipped (out of lower bound)",
					TTInt16(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt16 not clipped (within range)",
					TTInt16(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt16(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt16 clipped (out of upper bound)",
					TTInt16(v1) == -4,
					testAssertionCount,
					errorCount);

	// TTUInt16

	v1.clip(6, 12);
	TTTestAssertion("positive TTUInt16 clipped (out of lower bound)",
					TTUInt16(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTUInt16(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTUInt16 not clipped (within range)",
					TTUInt16(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTUInt16(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTUInt16 clipped (out of upper bound)",
					TTUInt16(v1) == 2,
					testAssertionCount,
					errorCount);

	// TTInt32

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt32 clipped (out of lower bound)",
					TTInt32(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt32 not clipped (within range)",
					TTInt32(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt32 clipped (out of upper bound)",
					TTInt32(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt32 clipped (out of lower bound)",
					TTInt32(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt32 not clipped (within range)",
					TTInt32(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt32(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt32 clipped (out of upper bound)",
					TTInt32(v1) == -4,
					testAssertionCount,
					errorCount);

	// TTUInt32

	v1.clip(6, 12);
	TTTestAssertion("positive TTUInt32 clipped (out of lower bound)",
					TTUInt32(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTUInt32(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTUInt32 not clipped (within range)",
					TTUInt32(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTUInt32(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTUInt32 clipped (out of upper bound)",
					TTUInt32(v1) == 2,
					testAssertionCount,
					errorCount);

	// TTInt64

	v1.clip(6, 12);
	TTTestAssertion("positive TTInt64 clipped (out of lower bound)",
					TTInt64(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTInt64 not clipped (within range)",
					TTInt64(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTInt64 clipped (out of upper bound)",
					TTInt64(v1) == 2,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(-3);
	v1.clip(-2, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt64 clipped (out of lower bound)",
					TTInt64(v1) == -2,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(-3);
	v1.clip(-4, 0);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt64 not clipped (within range)",
					TTInt64(v1) == -3,
					testAssertionCount,
					errorCount);

	v1 = TTInt64(-3);
	v1.clip(-8, -4);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("negative TTInt64 clipped (out of upper bound)",
					TTInt64(v1) == -4,
					testAssertionCount,
					errorCount);

	// TTUInt64

	v1.clip(6, 12);
	TTTestAssertion("positive TTUInt64 clipped (out of lower bound)",
					TTUInt64(v1) == 6,
					testAssertionCount,
					errorCount);

	v1 = TTUInt64(3);
	v1.clip(0, 4);
	TTTestAssertion("positive TTUInt64 not clipped (within range)",
					TTUInt64(v1) == 3,
					testAssertionCount,
					errorCount);

	v1 = TTUInt64(3);
	v1.clip(0, 2);
	// TTFloat64 myFloat = v1.get;
	TTTestAssertion("positive TTUInt64 clipped (out of upper bound)",
					TTUInt64(v1) == 2,
					testAssertionCount,
					errorCount);

	// TODO: test cliplow()
	/****************************************************************************************************/
	// TTTestLog("\n");
	// TTTestLog("Testing cliplow()");
	/****************************************************************************************************/

	// TODO: test cliphigh()
	/****************************************************************************************************/
	// TTTestLog("\n");
	// TTTestLog("Testing cliphigh()");
	/****************************************************************************************************/

	// TODO: test round()
	/****************************************************************************************************/
	// TTTestLog("\n");
	// TTTestLog("Testing round()");
	/****************************************************************************************************/

	// TODO: test truncate()
	/****************************************************************************************************/
	// TTTestLog("\n");
	// TTTestLog("Testing truncate()");
	/****************************************************************************************************/

	// TODO: test booleanize()
	/****************************************************************************************************/
	// TTTestLog("\n");
	// TTTestLog("Testing booleanize()");
	/****************************************************************************************************/

}

void TTValueTestOperators(int& errorCount, int&testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing TTValue operators");

	// TODO: test >
	// TODO: test ==
	// TODO: test =
	// TODO: test casting
	// TODO: should + be concatenating elements to create a new value of a+b element count?

	TTValue v1(3.14);
}

// TODO: Benchmarking

TTErr TTValueTest::test(TTValue& returnedTestInfo)
{
	int	errorCount = 0;
	int testAssertionCount = 0;

	TTValueTestBasic(errorCount, testAssertionCount);
	TTValueTestStringConversion(errorCount, testAssertionCount);
	TTValueTestNumericTransformations(errorCount, testAssertionCount);
	TTValueTestOperators(errorCount, testAssertionCount);

	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2017 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <boost/dll.hpp>
#include <boost/filesystem.hpp>

#include "core/logger.h"
#include "core/registry.h"
#include "core/version.h"
#include "elements/all.h"
#include "nodes/all.h"

namespace fs = boost::filesystem;
namespace dll = boost::dll;

inline void init_resources()
{
  Q_INIT_RESOURCE(icons);
}

namespace core {

Registry &Registry::get()
{
  static Registry s_registry{};
  return s_registry;
}

Registry::Registry()
{
  log::init();

  log::info("Spaghetti version: {}, git: {}@{}, build date: {}, {}", version::STRING, version::BRANCH,
            version::COMMIT_SHORT_HASH, __DATE__, __TIME__);
}

void Registry::registerInternalElements()
{
  init_resources();

  using namespace elements;

  registerElement<Package>("Package", ":/logic/package.png");

  registerElement<arithmetic::Add>("Add (Float)", ":/unknown.png");
  registerElement<arithmetic::AddIf>("Add If (Float)", ":/unknown.png");
  registerElement<arithmetic::Multiply>("Multiply (Float)", ":/unknown.png");
  registerElement<arithmetic::MultiplyIf>("Multiply If (Float)", ":/unknown.png");

  registerElement<gates::And>("AND (Bool)", ":/gates/and.png");
  registerElement<gates::Nand>("NAND (Bool)", ":/gates/nand.png");
  registerElement<gates::Nor>("NOR (Bool)", ":/gates/nor.png");
  registerElement<gates::Not>("NOT (Bool)", ":/gates/not.png");
  registerElement<gates::Or>("OR (Bool)", ":/gates/or.png");

  registerElement<logic::IfGreaterEqual>("If A >= B (Float)", ":/unknown.png");
  registerElement<logic::IfGreater>("If A > B (Float)", ":/unknown.png");
  registerElement<logic::IfEqual>("If A == B (Float)", ":/unknown.png");
  registerElement<logic::IfLower>("If A < B (Float)", ":/unknown.png");
  registerElement<logic::IfLowerEqual>("If A <= B (Float)", ":/unknown.png");

  registerElement<logic::Blinker, nodes::logic::Blinker>("Blinker (Bool)", ":/unknown.png");
  registerElement<logic::Clock, nodes::logic::Clock>("Clock (ms)", ":/logic/clock.png");
  registerElement<logic::Switch>("Switch (Int)", ":/logic/switch.png");

  registerElement<ui::FloatInfo, nodes::ui::FloatInfo>("Info (Float)", ":/values/const_float.png");
  registerElement<ui::IntInfo, nodes::ui::IntInfo>("Info (Int)", ":/values/const_int.png");
  registerElement<ui::PushButton, nodes::ui::PushButton>("Push Button (Bool)", ":/ui/push_button.png");
  registerElement<ui::ToggleButton, nodes::ui::ToggleButton>("Toggle Button (Bool)", ":/ui/toggle_button.png");

  registerElement<values::ConstBool, nodes::values::ConstBool>("Const value (Bool)", ":/values/const_bool.png");
  registerElement<values::ConstFloat, nodes::values::ConstFloat>("Const value (Float)", ":/values/const_float.png");
  registerElement<values::ConstInt, nodes::values::ConstInt>("Const value (Int)", ":/values/const_int.png");
  registerElement<values::RandomBool>("Random (Bool)", ":/values/random_value.png");

  registerElement<values::Int2Float>("Int2Float", ":/unknown.png");
  registerElement<values::Float2Int>("Float2Int", ":/unknown.png");
  registerElement<values::Degree2Radian>("Degree2Radian", ":/unknown.png");
  registerElement<values::Radian2Degree>("Radian2Degree", ":/unknown.png");

  registerElement<values::MinInt>("Minimum value (Int)", ":/unknown.png");
  registerElement<values::MaxInt>("Maximum value (Int)", ":/unknown.png");
  registerElement<values::MinFloat>("Minimum value (Float)", ":/unknown.png");
  registerElement<values::MaxFloat>("Maximum value (Float)", ":/unknown.png");

  registerElement<values::ClampFloat>("Clamp value (Float)", ":/unknown.png");
  registerElement<values::ClampInt>("Clamp value (Int)", ":/unknown.png");
}

void Registry::loadPlugins()
{
  fs::path const pluginsDir{ "../plugins" };

  if (!fs::is_directory(pluginsDir)) return;

  for (auto const &entry : fs::directory_iterator(pluginsDir)) {
    if (!fs::is_regular_file(entry)) continue;

    boost::system::error_code error{};
    auto plugin = std::make_shared<dll::shared_library>(entry, error, dll::load_mode::append_decorations);

    if (error.value() != 0 || !plugin->has("register_plugin")) continue;

    auto registerPlugin = plugin->get<void(core::Registry &)>("register_plugin");
    registerPlugin(*this);

    m_plugins.emplace_back(std::move(plugin));
  }
}

} // namespace core
<commit_msg>Normalize elements names<commit_after>// MIT License
//
// Copyright (c) 2017 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <boost/dll.hpp>
#include <boost/filesystem.hpp>

#include "core/logger.h"
#include "core/registry.h"
#include "core/version.h"
#include "elements/all.h"
#include "nodes/all.h"

namespace fs = boost::filesystem;
namespace dll = boost::dll;

inline void init_resources()
{
  Q_INIT_RESOURCE(icons);
}

namespace core {

Registry &Registry::get()
{
  static Registry s_registry{};
  return s_registry;
}

Registry::Registry()
{
  log::init();

  log::info("Spaghetti version: {}, git: {}@{}, build date: {}, {}", version::STRING, version::BRANCH,
            version::COMMIT_SHORT_HASH, __DATE__, __TIME__);
}

void Registry::registerInternalElements()
{
  init_resources();

  using namespace elements;

  registerElement<Package>("Package", ":/logic/package.png");

  registerElement<arithmetic::Add>("Add (Float)", ":/unknown.png");
  registerElement<arithmetic::AddIf>("Add If (Float)", ":/unknown.png");
  registerElement<arithmetic::Multiply>("Multiply (Float)", ":/unknown.png");
  registerElement<arithmetic::MultiplyIf>("Multiply If (Float)", ":/unknown.png");

  registerElement<gates::And>("AND (Bool)", ":/gates/and.png");
  registerElement<gates::Nand>("NAND (Bool)", ":/gates/nand.png");
  registerElement<gates::Nor>("NOR (Bool)", ":/gates/nor.png");
  registerElement<gates::Not>("NOT (Bool)", ":/gates/not.png");
  registerElement<gates::Or>("OR (Bool)", ":/gates/or.png");

  registerElement<logic::IfGreaterEqual>("If A >= B (Float)", ":/unknown.png");
  registerElement<logic::IfGreater>("If A > B (Float)", ":/unknown.png");
  registerElement<logic::IfEqual>("If A == B (Float)", ":/unknown.png");
  registerElement<logic::IfLower>("If A < B (Float)", ":/unknown.png");
  registerElement<logic::IfLowerEqual>("If A <= B (Float)", ":/unknown.png");

  registerElement<logic::Blinker, nodes::logic::Blinker>("Blinker (Bool)", ":/unknown.png");
  registerElement<logic::Clock, nodes::logic::Clock>("Clock (ms)", ":/logic/clock.png");
  registerElement<logic::Switch>("Switch (Int)", ":/logic/switch.png");

  registerElement<ui::FloatInfo, nodes::ui::FloatInfo>("Info (Float)", ":/values/const_float.png");
  registerElement<ui::IntInfo, nodes::ui::IntInfo>("Info (Int)", ":/values/const_int.png");
  registerElement<ui::PushButton, nodes::ui::PushButton>("Push Button (Bool)", ":/ui/push_button.png");
  registerElement<ui::ToggleButton, nodes::ui::ToggleButton>("Toggle Button (Bool)", ":/ui/toggle_button.png");

  registerElement<values::ConstBool, nodes::values::ConstBool>("Const value (Bool)", ":/values/const_bool.png");
  registerElement<values::ConstFloat, nodes::values::ConstFloat>("Const value (Float)", ":/values/const_float.png");
  registerElement<values::ConstInt, nodes::values::ConstInt>("Const value (Int)", ":/values/const_int.png");
  registerElement<values::RandomBool>("Random value (Bool)", ":/values/random_value.png");

  registerElement<values::Degree2Radian>("Convert angle (Deg2Rad)", ":/unknown.png");
  registerElement<values::Radian2Degree>("Convert angle (Rad2Deg)", ":/unknown.png");
  registerElement<values::Int2Float>("Convert value (Int2Float)", ":/unknown.png");
  registerElement<values::Float2Int>("Convert value (Float2Int)", ":/unknown.png");

  registerElement<values::MinInt>("Minimum value (Int)", ":/unknown.png");
  registerElement<values::MaxInt>("Maximum value (Int)", ":/unknown.png");
  registerElement<values::MinFloat>("Minimum value (Float)", ":/unknown.png");
  registerElement<values::MaxFloat>("Maximum value (Float)", ":/unknown.png");

  registerElement<values::ClampFloat>("Clamp value (Float)", ":/unknown.png");
  registerElement<values::ClampInt>("Clamp value (Int)", ":/unknown.png");
}

void Registry::loadPlugins()
{
  fs::path const pluginsDir{ "../plugins" };

  if (!fs::is_directory(pluginsDir)) return;

  for (auto const &entry : fs::directory_iterator(pluginsDir)) {
    if (!fs::is_regular_file(entry)) continue;

    boost::system::error_code error{};
    auto plugin = std::make_shared<dll::shared_library>(entry, error, dll::load_mode::append_decorations);

    if (error.value() != 0 || !plugin->has("register_plugin")) continue;

    auto registerPlugin = plugin->get<void(core::Registry &)>("register_plugin");
    registerPlugin(*this);

    m_plugins.emplace_back(std::move(plugin));
  }
}

} // namespace core
<|endoftext|>


<commit_before>
#include <string>

#include <windows.h>
#include <shlobj.h>

#include "./linc_dialogs.h"

namespace linc {

    namespace dialogs {

        //forward declare common helper
      std::string open_select_path(int type, const std::string &title, const std::vector<lincDialogsFilter> &filters);
      std::string dialog_folder(const std::string &title);

//Haxe facing calls

      ::String open(::String title, ::Array<Dynamic> filters) {

        std::vector<lincDialogsFilter> filter_list;
        int size = filters->size();
        for(int i=0; i<size; ++i) {
          filter_list.push_back(lincDialogsFilter(filters[i]));
        }
        std::string result = open_select_path(0, std::string(title.c_str()), filter_list);

        return ::String(result.c_str());

      } //open

      ::String save(::String title, Dynamic filter) {
        std::vector<lincDialogsFilter> filter_list;
        filter_list.push_back(lincDialogsFilter(filter));
        std::string result = open_select_path(1, std::string(title.c_str()), filter_list);

        return ::String(result.c_str());
      } //save

      ::String folder(::String title) {
        std::string result = dialog_folder(std::string(title.c_str()));

        return ::String(result.c_str());
      } //folder

      std::string lpw_to_stdstring(const LPWSTR str, UINT page = CP_ACP) {

        std::string result; char* cstr = 0;
        int len;

        len = WideCharToMultiByte(page, 0, str, -1, 0,  0, 0, 0);
        if (len > 0) {
          cstr = new char[len];
          int res = WideCharToMultiByte(page, 0, str, -1, cstr, len, 0, 0);
          if (res != 0) {
            cstr[len-1] = 0;
            result = std::string(cstr);
          }
          delete [] cstr;
        }

        return result;

      } //lpw_to_stdstring

      std::string dialog_folder(const std::string &title) {

        std::string path;

        HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

        if(SUCCEEDED(hr)) {

          IFileDialog *folder_dialog;

          hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&folder_dialog));

          if(SUCCEEDED(hr)) {

            DWORD folder_options;
            if (SUCCEEDED(folder_dialog->GetOptions(&folder_options))) {
              folder_dialog->SetOptions(folder_options | FOS_PICKFOLDERS);
            }

            hr = folder_dialog->Show(NULL);

            if(SUCCEEDED(hr)) {

              IShellItem *_item;
              hr = folder_dialog->GetResult(&_item);

              if(SUCCEEDED(hr)) {

                LPWSTR selected_path = NULL;
                hr = _item->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &selected_path);

                if(SUCCEEDED(hr)) {
                  path = lpw_to_stdstring(selected_path);
                  CoTaskMemFree(selected_path);
                }

                _item->Release();

              } //get result

            } //show

            folder_dialog->Release();

          } //create folder dialog

          CoUninitialize();

        } //coinitialize

        return path;

      } //dialog_folder

      //common helper
      //type 0 == file open
      //type 1 == file save
      std::string open_select_path(int type, const std::string &title, const std::vector<lincDialogsFilter> &filters) {

        OPENFILENAME ofn;
        char path[MAX_PATH] = "";
        std::string final;

        ZeroMemory(&ofn, sizeof(ofn));

        ofn.lStructSize = sizeof(ofn);

        ofn.lpstrFile = path;
        ofn.lpstrTitle = title.c_str();
        ofn.nMaxFile = MAX_PATH;
        ofn.Flags = 0;

        //:todo:
        // ofn.lpstrDefExt = "*";
        if(filters.size()) {

          std::vector<lincDialogsFilter>::const_iterator it = filters.begin();
          for( ; it != filters.end(); ++it) {

            lincDialogsFilter filter = (*it);

            std::string _desc(filter.desc.c_str());
            std::string _ext(filter.ext.c_str());
            final += _desc + " (*." + _ext + ")";
            final.push_back('\0');
            final += "*." + _ext;
            final.push_back('\0');

          } //each filter

          final.push_back('\0');
          ofn.lpstrFilter = final.c_str();

        } else {
          ofn.lpstrFilter = "All Files (*.*)\0*.*\0";
        }

        if(type == 0) {

          ofn.Flags |= OFN_HIDEREADONLY;
          ofn.Flags |= OFN_FILEMUSTEXIST;

          if(GetOpenFileName(&ofn)) {
            return std::string( ofn.lpstrFile );
          }

        } else if(type == 1) {

          ofn.Flags |= OFN_OVERWRITEPROMPT;

          if(GetSaveFileName(&ofn)) {
            return std::string( ofn.lpstrFile );
          }

        }

        return std::string();

      } //open_select_file

    } //dialogs namespace

} //linc namespace
<commit_msg>Fixed optional / null args for windows<commit_after>
#include <string>

#include <windows.h>
#include <shlobj.h>

#include "./linc_dialogs.h"

namespace linc {

    namespace dialogs {

        //forward declare common helper
      std::string open_select_path(int type, const std::string &title, const std::vector<lincDialogsFilter> &filters);
      std::string dialog_folder(const std::string &title);

//Haxe facing calls

      ::String open(::String title, ::Array<Dynamic> filters) {

        std::vector<lincDialogsFilter> filter_list;
        if (filters!=null()) {
          int size = filters->size();
          for(int i=0; i<size; ++i) {
            filter_list.push_back(lincDialogsFilter(filters[i]));
          }
        }
        std::string result = open_select_path(0, std::string(title.c_str()), filter_list);

        return ::String(result.c_str());

      } //open

      ::String save(::String title, Dynamic filter) {
        std::vector<lincDialogsFilter> filter_list;
        if (filter!=null()) filter_list.push_back(lincDialogsFilter(filter));
        std::string result = open_select_path(1, std::string(title.c_str()), filter_list);

        return ::String(result.c_str());
      } //save

      ::String folder(::String title) {
        std::string result = dialog_folder(std::string(title.c_str()));

        return ::String(result.c_str());
      } //folder

      std::string lpw_to_stdstring(const LPWSTR str, UINT page = CP_ACP) {

        std::string result; char* cstr = 0;
        int len;

        len = WideCharToMultiByte(page, 0, str, -1, 0,  0, 0, 0);
        if (len > 0) {
          cstr = new char[len];
          int res = WideCharToMultiByte(page, 0, str, -1, cstr, len, 0, 0);
          if (res != 0) {
            cstr[len-1] = 0;
            result = std::string(cstr);
          }
          delete [] cstr;
        }

        return result;

      } //lpw_to_stdstring

      std::string dialog_folder(const std::string &title) {

        std::string path;

        HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

        if(SUCCEEDED(hr)) {

          IFileDialog *folder_dialog;

          hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&folder_dialog));

          if(SUCCEEDED(hr)) {

            DWORD folder_options;
            if (SUCCEEDED(folder_dialog->GetOptions(&folder_options))) {
              folder_dialog->SetOptions(folder_options | FOS_PICKFOLDERS);
            }

            hr = folder_dialog->Show(NULL);

            if(SUCCEEDED(hr)) {

              IShellItem *_item;
              hr = folder_dialog->GetResult(&_item);

              if(SUCCEEDED(hr)) {

                LPWSTR selected_path = NULL;
                hr = _item->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &selected_path);

                if(SUCCEEDED(hr)) {
                  path = lpw_to_stdstring(selected_path);
                  CoTaskMemFree(selected_path);
                }

                _item->Release();

              } //get result

            } //show

            folder_dialog->Release();

          } //create folder dialog

          CoUninitialize();

        } //coinitialize

        return path;

      } //dialog_folder

      //common helper
      //type 0 == file open
      //type 1 == file save
      std::string open_select_path(int type, const std::string &title, const std::vector<lincDialogsFilter> &filters) {

        OPENFILENAME ofn;
        char path[MAX_PATH] = "";
        std::string final;

        ZeroMemory(&ofn, sizeof(ofn));

        ofn.lStructSize = sizeof(ofn);

        ofn.lpstrFile = path;
        ofn.lpstrTitle = title.c_str();
        ofn.nMaxFile = MAX_PATH;
        ofn.Flags = 0;

        //:todo:
        // ofn.lpstrDefExt = "*";
        if(filters.size()) {

          std::vector<lincDialogsFilter>::const_iterator it = filters.begin();
          for( ; it != filters.end(); ++it) {

            lincDialogsFilter filter = (*it);

            std::string _desc(filter.desc.c_str());
            std::string _ext(filter.ext.c_str());
            final += _desc + " (*." + _ext + ")";
            final.push_back('\0');
            final += "*." + _ext;
            final.push_back('\0');

          } //each filter

          final.push_back('\0');
          ofn.lpstrFilter = final.c_str();

        } else {
          ofn.lpstrFilter = "All Files (*.*)\0*.*\0";
        }

        if(type == 0) {

          ofn.Flags |= OFN_HIDEREADONLY;
          ofn.Flags |= OFN_FILEMUSTEXIST;

          if(GetOpenFileName(&ofn)) {
            return std::string( ofn.lpstrFile );
          }

        } else if(type == 1) {

          ofn.Flags |= OFN_OVERWRITEPROMPT;

          if(GetSaveFileName(&ofn)) {
            return std::string( ofn.lpstrFile );
          }

        }

        return std::string();

      } //open_select_file

    } //dialogs namespace

} //linc namespace
<|endoftext|>


<commit_before>#include "word-tag.hpp"
#include "fast-sprintf.hpp"

extern "C" {
#ifdef DEBUG
#include <build-disjuncts.h>      // for prt_exp_mem()
#include <dict-api.h>             // for print_expression()
#endif
#include "error.h"
#include "utilities.h"
}

#define D_IC 6
void WordTag::insert_connectors(Exp* exp, int& dfs_position,
                                bool& leading_right, bool& leading_left,
                                std::vector<int>& eps_right,
                                std::vector<int>& eps_left,
                                char* var, bool root, double parent_cost,
                                Exp* parent_exp, const X_node *word_xnode)
{
  double cost = parent_cost + exp->cost;

#ifdef DEBUG
  if (0 && debug_level(+D_IC)) { // Extreme debug
    printf("Expression type %d for Word%d, var %s:\n", exp->type, _word, var);
    printf("parent_exp: "); print_expression(parent_exp);
    printf("exp: "); print_expression(exp);
  }
#endif

  if (exp->type == CONNECTOR_type) {
    dfs_position++;

    const char* name = exp->u.string;

    Connector connector;
    init_connector(&connector);
    connector.multi = exp->multi;
    connector.string = name;
    set_connector_length_limit(&connector);

    switch (exp->dir) {
    case '+':
      _position.push_back(_right_connectors.size());
      _dir.push_back('+');
      _right_connectors.push_back(
           PositionConnector(parent_exp, &connector, '+', _word, dfs_position,
                             exp->cost, cost, leading_right, false,
                             eps_right, eps_left, word_xnode));
      leading_right = false;
      break;
    case '-':
      _position.push_back(_left_connectors.size());
      _dir.push_back('-');
      _left_connectors.push_back(
           PositionConnector(parent_exp, &connector, '-', _word, dfs_position,
                             exp->cost, cost, false, leading_left,
                             eps_right, eps_left, word_xnode));
      leading_left = false;
      break;
    default:
      throw std::string("Unknown connector direction: ") + exp->dir;
    }
  } else if (exp->type == AND_type) {
    if (exp->u.l == NULL) {
      /* zeroary and */
    } else
      if (exp->u.l != NULL && exp->u.l->next == NULL) {
        /* unary and - skip */
        insert_connectors(exp->u.l->e, dfs_position, leading_right,
             leading_left, eps_right, eps_left, var, root, cost, parent_exp, word_xnode);
      } else {
        int i;
        E_list* l;

        char new_var[MAX_VARIABLE_NAME];
        char* last_new_var = new_var;
        char* last_var = var;
        while ((*last_new_var = *last_var)) {
          last_new_var++;
          last_var++;
        }

        for (i = 0, l = exp->u.l; l != NULL; l = l->next, i++) {
          char* s = last_new_var;
          *s++ = 'c';
          fast_sprintf(s, i);

          insert_connectors(l->e, dfs_position, leading_right, leading_left,
                eps_right, eps_left, new_var, false, cost, parent_exp, word_xnode);

          if (leading_right && var != NULL) {
            eps_right.push_back(_variables->epsilon(new_var, '+'));
          }
          if (leading_left && var != NULL) {
            eps_left.push_back(_variables->epsilon(new_var, '-'));
          }
        }
      }
  } else if (exp->type == OR_type) {
    if (exp->u.l != NULL && exp->u.l->next == NULL) {
      /* unary or - skip */
      insert_connectors(exp->u.l->e, dfs_position, leading_right, leading_left,
          eps_right, eps_left, var, root, cost, exp->u.l->e, word_xnode);
    } else {
      int i;
      E_list* l;
      bool ll_true = false;
      bool lr_true = false;

      char new_var[MAX_VARIABLE_NAME];
      char* last_new_var = new_var;
      char* last_var = var;
      while ((*last_new_var = *last_var)) {
        last_new_var++;
        last_var++;
      }

#ifdef DEBUG
      if (0 && debug_level(+D_IC)) { // Extreme debug
        printf("Word%d, var %s OR_type:\n", _word, var);
        printf("exp mem: "); prt_exp_mem(exp, 0);
      }
#endif

      for (i = 0, l = exp->u.l; l != NULL; l = l->next, i++) {
        bool lr = leading_right, ll = leading_left;
        std::vector<int> er = eps_right, el = eps_left;

        char* s = last_new_var;
        *s++ = 'd';
        fast_sprintf(s, i);

        lgdebug(+D_IC, "Word%d: var: %s; exp%d=%p; X_node: %s\n",
                _word, var, i, l, word_xnode ? word_xnode->word->subword : "NULL X_node");
        assert(word_xnode != NULL, "NULL X_node for var %s", new_var);
        if (root && parent_exp == NULL && l->e != word_xnode->exp) {
          E_list *we = NULL;

          if (word_xnode->exp->type == OR_type) {
            for (we = word_xnode->exp->u.l; we != NULL; we = we-> next)
            {
              if (l->e == we->e)
                break;
            }
          }
          if (we == NULL) {
            lgdebug(+D_IC, "Next word_xnode for word %d is needed\n", _word);
            word_xnode = word_xnode->next;
            assert(word_xnode != NULL, "NULL next X_node for var %s", new_var);
          }
        }
        insert_connectors(l->e, dfs_position, lr, ll, er, el, new_var, false, cost, l->e, word_xnode);

        if (lr)
          lr_true = true;
        if (ll)
          ll_true = true;
      }
      leading_right = lr_true;
      leading_left = ll_true;
    }
  }
}
#undef D_IC

void WordTag::find_matches(int w, const char* C, char dir, std::vector<PositionConnector*>& matches)
{
  //  cout << "Look connection on: ." << _word << ". ." << w << ". " << C << dir << endl;
  Connector search_cntr;
  init_connector(&search_cntr);
  search_cntr.string = C;
  set_connector_length_limit(&search_cntr);

  std::vector<PositionConnector>* connectors;
  switch(dir) {
  case '+':
    connectors = &_left_connectors;
    break;
  case '-':
    connectors = &_right_connectors;
    break;
  default:
    throw std::string("Unknown connector direction: ") + dir;
  }

  std::vector<PositionConnector>::iterator i;
  for (i = connectors->begin(); i != connectors->end(); i++) {
    if (WordTag::match(w, search_cntr, dir, (*i).word, ((*i).connector))) {
      matches.push_back(&(*i));
    }
  }
}

void WordTag::add_matches_with_word(WordTag& tag)
{
  std::vector<PositionConnector>::iterator i;
  for (i = _right_connectors.begin(); i != _right_connectors.end(); i++) {
    std::vector<PositionConnector*> connector_matches;
    tag.find_matches(_word, (*i).connector.string, '+', connector_matches);
    std::vector<PositionConnector*>::iterator j;
    for (j = connector_matches.begin(); j != connector_matches.end(); j++) {
      i->matches.push_back(*j);
      set_match_possible((*j)->word, (*j)->position);
      (*j)->matches.push_back(&(*i));
      tag.set_match_possible(_word, (*i).position);
    }
  }
}
<commit_msg>Fix "Assertion (word_xnode != NULL) failed" in SAT solver<commit_after>#include "word-tag.hpp"
#include "fast-sprintf.hpp"

extern "C" {
#ifdef DEBUG
#include <build-disjuncts.h>      // for prt_exp_mem()
#include <dict-api.h>             // for print_expression()
#endif
#include "error.h"
#include "utilities.h"
}

#define D_IC 6
void WordTag::insert_connectors(Exp* exp, int& dfs_position,
                                bool& leading_right, bool& leading_left,
                                std::vector<int>& eps_right,
                                std::vector<int>& eps_left,
                                char* var, bool root, double parent_cost,
                                Exp* parent_exp, const X_node *word_xnode)
{
  double cost = parent_cost + exp->cost;

#ifdef DEBUG
  if (0 && debug_level(+D_IC)) { // Extreme debug
    printf("Expression type %d for Word%d, var %s:\n", exp->type, _word, var);
    printf("parent_exp: "); print_expression(parent_exp);
    printf("exp: "); print_expression(exp);
  }
#endif

  if (exp->type == CONNECTOR_type) {
    dfs_position++;

    const char* name = exp->u.string;

    Connector connector;
    init_connector(&connector);
    connector.multi = exp->multi;
    connector.string = name;
    set_connector_length_limit(&connector);

    switch (exp->dir) {
    case '+':
      _position.push_back(_right_connectors.size());
      _dir.push_back('+');
      _right_connectors.push_back(
           PositionConnector(parent_exp, &connector, '+', _word, dfs_position,
                             exp->cost, cost, leading_right, false,
                             eps_right, eps_left, word_xnode));
      leading_right = false;
      break;
    case '-':
      _position.push_back(_left_connectors.size());
      _dir.push_back('-');
      _left_connectors.push_back(
           PositionConnector(parent_exp, &connector, '-', _word, dfs_position,
                             exp->cost, cost, false, leading_left,
                             eps_right, eps_left, word_xnode));
      leading_left = false;
      break;
    default:
      throw std::string("Unknown connector direction: ") + exp->dir;
    }
  } else if (exp->type == AND_type) {
    if (exp->u.l == NULL) {
      /* zeroary and */
    } else
      if (exp->u.l != NULL && exp->u.l->next == NULL) {
        /* unary and - skip */
        insert_connectors(exp->u.l->e, dfs_position, leading_right,
             leading_left, eps_right, eps_left, var, root, cost, parent_exp, word_xnode);
      } else {
        int i;
        E_list* l;

        char new_var[MAX_VARIABLE_NAME];
        char* last_new_var = new_var;
        char* last_var = var;
        while ((*last_new_var = *last_var)) {
          last_new_var++;
          last_var++;
        }

        for (i = 0, l = exp->u.l; l != NULL; l = l->next, i++) {
          char* s = last_new_var;
          *s++ = 'c';
          fast_sprintf(s, i);

          insert_connectors(l->e, dfs_position, leading_right, leading_left,
                eps_right, eps_left, new_var, false, cost, parent_exp, word_xnode);

          if (leading_right && var != NULL) {
            eps_right.push_back(_variables->epsilon(new_var, '+'));
          }
          if (leading_left && var != NULL) {
            eps_left.push_back(_variables->epsilon(new_var, '-'));
          }
        }
      }
  } else if (exp->type == OR_type) {
    if (exp->u.l != NULL && exp->u.l->next == NULL) {
      /* unary or - skip */
      insert_connectors(exp->u.l->e, dfs_position, leading_right, leading_left,
          eps_right, eps_left, var, root, cost, exp->u.l->e, word_xnode);
    } else {
      int i;
      E_list* l;
      bool ll_true = false;
      bool lr_true = false;

      char new_var[MAX_VARIABLE_NAME];
      char* last_new_var = new_var;
      char* last_var = var;
      while ((*last_new_var = *last_var)) {
        last_new_var++;
        last_var++;
      }

#ifdef DEBUG
      if (0 && debug_level(+D_IC)) { // Extreme debug
        printf("Word%d, var %s OR_type:\n", _word, var);
        printf("exp mem: "); prt_exp_mem(exp, 0);
      }
#endif

      for (i = 0, l = exp->u.l; l != NULL; l = l->next, i++) {
        bool lr = leading_right, ll = leading_left;
        std::vector<int> er = eps_right, el = eps_left;

        char* s = last_new_var;
        *s++ = 'd';
        fast_sprintf(s, i);

        lgdebug(+D_IC, "Word%d: var: %s; exp%d=%p; X_node: %s\n",
                _word, var, i, l, word_xnode ? word_xnode->word->subword : "NULL X_node");
        assert(word_xnode != NULL, "NULL X_node for var %s", new_var);
        if (root && parent_exp == NULL && l->e != word_xnode->exp) {
          E_list *we = NULL;

          if (word_xnode->exp->type == OR_type) {
            for (we = word_xnode->exp->u.l; we != NULL; we = we-> next) {
              if (l->e == we->e)
                break;
            }
          }
          if (we == NULL && word_xnode->next != NULL) {
            lgdebug(+D_IC, "Next word_xnode for word %d is needed\n", _word);
            word_xnode = word_xnode->next;
          }
        }
        insert_connectors(l->e, dfs_position, lr, ll, er, el, new_var, false, cost, l->e, word_xnode);

        if (lr)
          lr_true = true;
        if (ll)
          ll_true = true;
      }
      leading_right = lr_true;
      leading_left = ll_true;
    }
  }
}
#undef D_IC

void WordTag::find_matches(int w, const char* C, char dir, std::vector<PositionConnector*>& matches)
{
  //  cout << "Look connection on: ." << _word << ". ." << w << ". " << C << dir << endl;
  Connector search_cntr;
  init_connector(&search_cntr);
  search_cntr.string = C;
  set_connector_length_limit(&search_cntr);

  std::vector<PositionConnector>* connectors;
  switch(dir) {
  case '+':
    connectors = &_left_connectors;
    break;
  case '-':
    connectors = &_right_connectors;
    break;
  default:
    throw std::string("Unknown connector direction: ") + dir;
  }

  std::vector<PositionConnector>::iterator i;
  for (i = connectors->begin(); i != connectors->end(); i++) {
    if (WordTag::match(w, search_cntr, dir, (*i).word, ((*i).connector))) {
      matches.push_back(&(*i));
    }
  }
}

void WordTag::add_matches_with_word(WordTag& tag)
{
  std::vector<PositionConnector>::iterator i;
  for (i = _right_connectors.begin(); i != _right_connectors.end(); i++) {
    std::vector<PositionConnector*> connector_matches;
    tag.find_matches(_word, (*i).connector.string, '+', connector_matches);
    std::vector<PositionConnector*>::iterator j;
    for (j = connector_matches.begin(); j != connector_matches.end(); j++) {
      i->matches.push_back(*j);
      set_match_possible((*j)->word, (*j)->position);
      (*j)->matches.push_back(&(*i));
      tag.set_match_possible(_word, (*i).position);
    }
  }
}
<|endoftext|>