<commit_before>/*
 * Initial version copied from https://github.com/JetBrains/intellij-community/blob/master/native/fsNotifier/mac/fsnotifier.c
 */
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.

/*
 * Apple specific functions.
 */
#if defined(__APPLE__)

#include "native.h"
#include "generic.h"
#include <CoreServices/CoreServices.h>
#include <pthread.h>
#include <strings.h>

JavaVM* jvm = NULL;
bool invalidStateDetected = false;

typedef struct watch_details {
    CFMutableArrayRef rootsToWatch;
    FSEventStreamRef watcherStream;
    pthread_t watcherThread;
    jobject watcherCallback;
    CFRunLoopRef threadLoop;
} watch_details_t;

static void reportEvent(jint type, char *path, watch_details_t *details) {
    // TODO What does this do?
    size_t len = 0;
    if (path != NULL) {
        len = strlen(path);
        for (char *p = path; *p != '\0'; p++) {
            if (*p == '\n') {
                *p = '\0';
            }
        }
    }

    // TODO Extract this logic to some global function
    JNIEnv* env;
    int getEnvStat = jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
    if (getEnvStat == JNI_EDETACHED) {
        if (jvm->AttachCurrentThread((void **) &env, NULL) != JNI_OK) {
            invalidStateDetected = true;
            return;
        }
    } else if (getEnvStat == JNI_EVERSION) {
        invalidStateDetected = true;
        return;
    }

    printf("~~~~ Changed: %s %d\n", path, type);

    jobject watcherCallback = details->watcherCallback;
    jclass callback_class = env->GetObjectClass(watcherCallback);
    jmethodID methodCallback = env->GetMethodID(callback_class, "pathChanged", "(ILjava/lang/String;)V");
    env->CallVoidMethod(watcherCallback, methodCallback, type, env->NewStringUTF(path));
}

static void callback(ConstFSEventStreamRef streamRef,
                     void *clientCallBackInfo,
                     size_t numEvents,
                     void *eventPaths,
                     const FSEventStreamEventFlags eventFlags[],
                     const FSEventStreamEventId eventIds[]) {
    if (invalidStateDetected) return;
    char **paths = (char**) eventPaths;

    watch_details_t *details = (watch_details_t*) clientCallBackInfo;

    for (int i = 0; i < numEvents; i++) {
        FSEventStreamEventFlags flags = eventFlags[i];
        printf("~~~~ Event flags: 0x%x for %s\n", flags, paths[i]);
        jint type;
        if (IS_SET(flags, kFSEventStreamEventFlagMustScanSubDirs)) {
            type = FILE_EVENT_INVALIDATE;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemRenamed)) {
            if (IS_SET(flags, kFSEventStreamEventFlagItemCreated)) {
                type = FILE_EVENT_REMOVED;
            } else {
                type = FILE_EVENT_CREATED;
            }
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemModified)) {
            type = FILE_EVENT_MODIFIED;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemRemoved)) {
            type = FILE_EVENT_REMOVED;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemCreated)) {
            type = FILE_EVENT_CREATED;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemInodeMetaMod)) {
            // File locked
            type = FILE_EVENT_MODIFIED;
        } else {
            printf("~~~~ Unknown event 0x%x for %s\n", flags, paths[i]);
            type = FILE_EVENT_UNKNOWN;
        }
        reportEvent(type, paths[i], details);
    }
}

static void *EventProcessingThread(void *data) {
    watch_details_t *details = (watch_details_t*) data;

    printf("~~~~ Starting thread\n");

    CFRunLoopRef threadLoop = CFRunLoopGetCurrent();
    FSEventStreamScheduleWithRunLoop(details->watcherStream, threadLoop, kCFRunLoopDefaultMode);
    FSEventStreamStart(details->watcherStream);
    details->threadLoop = threadLoop;
    // TODO We should wait for this in the caller thread otherwise stopWatching() might crash
    // This triggers run loop for this thread, causing it to run until we explicitly stop it.
    CFRunLoopRun();

    printf("~~~~ Stopping thread\n");

    return NULL;
}

void freeDetails(JNIEnv *env, watch_details_t *details) {
    CFMutableArrayRef rootsToWatch = details->rootsToWatch;
    FSEventStreamRef watcherStream = details->watcherStream;
    pthread_t watcherThread = details->watcherThread;
    jobject watcherCallback = details->watcherCallback;
    CFRunLoopRef threadLoop = details->threadLoop;
    free(details);

    if (threadLoop != NULL) {
        CFRunLoopStop(threadLoop);
    }

    if (watcherThread != NULL) {
        pthread_join(watcherThread, NULL);
    }

    if (rootsToWatch != NULL) {
        for (int i = 0; i < CFArrayGetCount(rootsToWatch); i++) {
            const void *value = CFArrayGetValueAtIndex(rootsToWatch, i);
            CFRelease(value);
        }
        // TODO Can we release these earlier?
        CFRelease(rootsToWatch);
    }

    if (watcherStream != NULL) {
        FSEventStreamStop(watcherStream);
        FSEventStreamInvalidate(watcherStream);
        FSEventStreamRelease(watcherStream);
        // TODO: consider using FSEventStreamFlushSync to flush all pending events.
    }

    if (watcherCallback != NULL) {
        env->DeleteGlobalRef(watcherCallback);
    }
}

JNIEXPORT jobject JNICALL
Java_net_rubygrapefruit_platform_internal_jni_OsxFileEventFunctions_startWatching(JNIEnv *env, jclass target, jobjectArray paths, long latencyInMillis, jobject javaCallback, jobject result) {

    printf("\n~~~~ Configuring...\n");

    invalidStateDetected = false;
    CFMutableArrayRef rootsToWatch = CFArrayCreateMutable(NULL, 0, NULL);
    if (rootsToWatch == NULL) {
        mark_failed_with_errno(env, "Could not allocate array to store roots to watch.", result);
        return NULL;
    }
    int count = env->GetArrayLength(paths);
    if (count == 0) {
        mark_failed_with_errno(env, "No paths given to watch.", result);
        return NULL;
    }

    watch_details_t* details = (watch_details_t*) malloc(sizeof(watch_details_t));
    details->rootsToWatch = rootsToWatch;
    for (int i = 0; i < count; i++) {
        jstring path = (jstring) env->GetObjectArrayElement(paths, i);
        char* watchedPath = java_to_char(env, path, result);
        printf("~~~~ Watching %s\n", watchedPath);
        if (watchedPath == NULL) {
            mark_failed_with_errno(env, "Could not allocate string to store root to watch.", result);
            freeDetails(env, details);
            return NULL;
        }
        CFStringRef stringPath = CFStringCreateWithCString(NULL, watchedPath, kCFStringEncodingUTF8);
        free(watchedPath);
        if (stringPath == NULL) {
            mark_failed_with_errno(env, "Could not create CFStringRef.", result);
            freeDetails(env, details);
            return NULL;
        }
        CFArrayAppendValue(rootsToWatch, stringPath);
    }

    details->watcherCallback = env->NewGlobalRef(javaCallback);
    if (details->watcherCallback == NULL) {
        mark_failed_with_errno(env, "Could not create global reference for callback.", result);
        freeDetails(env, details);
        return NULL;
    }

    FSEventStreamContext context = {0, (void*) details, NULL, NULL, NULL};
    details->watcherStream = FSEventStreamCreate (
                NULL,
                &callback,
                &context,
                rootsToWatch,
                kFSEventStreamEventIdSinceNow,
                latencyInMillis / 1000.0,
                kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents);
    if (details->watcherStream == NULL) {
        mark_failed_with_errno(env, "Could not create FSEventStreamCreate to track changes.", result);
        freeDetails(env, details);
        return NULL;
    }

    if (pthread_create(&(details->watcherThread), NULL, EventProcessingThread, details) != 0) {
        mark_failed_with_errno(env, "Could not create file watcher thread.", result);
        freeDetails(env, details);
        return NULL;
    }

    // TODO Should this be somewhere global?
    int jvmStatus = env->GetJavaVM(&jvm);
    if (jvmStatus < 0) {
        mark_failed_with_errno(env, "Could not store jvm instance.", result);
        freeDetails(env, details);
        return NULL;
    }

    jclass clsWatcher = env->FindClass("net/rubygrapefruit/platform/internal/jni/OsxFileEventFunctions$WatcherImpl");
    jmethodID constructor = env->GetMethodID(clsWatcher, "<init>", "(Ljava/lang/Object;)V");
    return env->NewObject(clsWatcher, constructor, env->NewDirectByteBuffer(details, sizeof(details)));
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_OsxFileEventFunctions_stopWatching(JNIEnv *env, jclass target, jobject detailsObj, jobject result) {
    watch_details_t *details = (watch_details_t*) env->GetDirectBufferAddress(detailsObj);

    if (invalidStateDetected) {
        // report and reset flag, but try to clean up state as much as possible
        mark_failed_with_errno(env, "Watcher is in invalid state, reported changes may be incorrect.", result);
    }

    freeDetails(env, details);
}

#endif
<commit_msg>Attach/detach JNI to watcher thread only once<commit_after>/*
 * Initial version copied from https://github.com/JetBrains/intellij-community/blob/master/native/fsNotifier/mac/fsnotifier.c
 */
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.

/*
 * Apple specific functions.
 */
#if defined(__APPLE__)

#include "native.h"
#include "generic.h"
#include <CoreServices/CoreServices.h>
#include <pthread.h>
#include <strings.h>

JavaVM* jvm = NULL;
bool invalidStateDetected = false;

typedef struct watch_details {
    CFMutableArrayRef rootsToWatch;
    FSEventStreamRef watcherStream;
    pthread_t watcherThread;
    JNIEnv *env;
    jobject watcherCallback;
    CFRunLoopRef threadLoop;
} watch_details_t;

static void reportEvent(jint type, char *path, watch_details_t *details) {
    // TODO What does this do?
    size_t len = 0;
    if (path != NULL) {
        len = strlen(path);
        for (char *p = path; *p != '\0'; p++) {
            if (*p == '\n') {
                *p = '\0';
            }
        }
    }

    printf("~~~~ Changed: %s %d\n", path, type);

    JNIEnv *env = details->env;
    jobject watcherCallback = details->watcherCallback;
    jclass callback_class = env->GetObjectClass(watcherCallback);
    jmethodID methodCallback = env->GetMethodID(callback_class, "pathChanged", "(ILjava/lang/String;)V");
    env->CallVoidMethod(watcherCallback, methodCallback, type, env->NewStringUTF(path));
}

static void callback(ConstFSEventStreamRef streamRef,
                     void *clientCallBackInfo,
                     size_t numEvents,
                     void *eventPaths,
                     const FSEventStreamEventFlags eventFlags[],
                     const FSEventStreamEventId eventIds[]) {
    if (invalidStateDetected) return;
    char **paths = (char**) eventPaths;

    watch_details_t *details = (watch_details_t*) clientCallBackInfo;

    for (int i = 0; i < numEvents; i++) {
        FSEventStreamEventFlags flags = eventFlags[i];
        printf("~~~~ Event flags: 0x%x for %s\n", flags, paths[i]);
        jint type;
        if (IS_SET(flags, kFSEventStreamEventFlagMustScanSubDirs)) {
            type = FILE_EVENT_INVALIDATE;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemRenamed)) {
            if (IS_SET(flags, kFSEventStreamEventFlagItemCreated)) {
                type = FILE_EVENT_REMOVED;
            } else {
                type = FILE_EVENT_CREATED;
            }
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemModified)) {
            type = FILE_EVENT_MODIFIED;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemRemoved)) {
            type = FILE_EVENT_REMOVED;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemCreated)) {
            type = FILE_EVENT_CREATED;
        } else if (IS_SET(flags, kFSEventStreamEventFlagItemInodeMetaMod)) {
            // File locked
            type = FILE_EVENT_MODIFIED;
        } else {
            printf("~~~~ Unknown event 0x%x for %s\n", flags, paths[i]);
            type = FILE_EVENT_UNKNOWN;
        }
        reportEvent(type, paths[i], details);
    }
}

static void *EventProcessingThread(void *data) {
    watch_details_t *details = (watch_details_t*) data;

    printf("~~~~ Starting thread\n");

    // TODO Extract this logic to some global function
    jint statAttach = jvm->AttachCurrentThreadAsDaemon((void **) &(details->env), NULL);
    if (statAttach != JNI_OK) {
        printf("Failed to attach JNI to current thread: %d\n", statAttach);
        invalidStateDetected = true;
        return NULL;
    }

    CFRunLoopRef threadLoop = CFRunLoopGetCurrent();
    FSEventStreamScheduleWithRunLoop(details->watcherStream, threadLoop, kCFRunLoopDefaultMode);
    FSEventStreamStart(details->watcherStream);
    details->threadLoop = threadLoop;
    // TODO We should wait for this in the caller thread otherwise stopWatching() might crash
    // This triggers run loop for this thread, causing it to run until we explicitly stop it.
    CFRunLoopRun();

    printf("~~~~ Stopping thread\n");

    jint statDetach = jvm->DetachCurrentThread();
    if (statDetach != JNI_OK) {
        printf("Failed to detach JNI from current thread: %d\n", statAttach);
        invalidStateDetected = true;
        return NULL;
    }

    return NULL;
}

void freeDetails(JNIEnv *env, watch_details_t *details) {
    CFMutableArrayRef rootsToWatch = details->rootsToWatch;
    FSEventStreamRef watcherStream = details->watcherStream;
    pthread_t watcherThread = details->watcherThread;
    jobject watcherCallback = details->watcherCallback;
    CFRunLoopRef threadLoop = details->threadLoop;
    free(details);

    if (threadLoop != NULL) {
        CFRunLoopStop(threadLoop);
    }

    if (watcherThread != NULL) {
        pthread_join(watcherThread, NULL);
    }

    if (rootsToWatch != NULL) {
        for (int i = 0; i < CFArrayGetCount(rootsToWatch); i++) {
            const void *value = CFArrayGetValueAtIndex(rootsToWatch, i);
            CFRelease(value);
        }
        // TODO Can we release these earlier?
        CFRelease(rootsToWatch);
    }

    if (watcherStream != NULL) {
        FSEventStreamStop(watcherStream);
        FSEventStreamInvalidate(watcherStream);
        FSEventStreamRelease(watcherStream);
        // TODO: consider using FSEventStreamFlushSync to flush all pending events.
    }

    if (watcherCallback != NULL) {
        env->DeleteGlobalRef(watcherCallback);
    }
}

JNIEXPORT jobject JNICALL
Java_net_rubygrapefruit_platform_internal_jni_OsxFileEventFunctions_startWatching(JNIEnv *env, jclass target, jobjectArray paths, long latencyInMillis, jobject javaCallback, jobject result) {

    printf("\n~~~~ Configuring...\n");

    invalidStateDetected = false;
    CFMutableArrayRef rootsToWatch = CFArrayCreateMutable(NULL, 0, NULL);
    if (rootsToWatch == NULL) {
        mark_failed_with_errno(env, "Could not allocate array to store roots to watch.", result);
        return NULL;
    }
    int count = env->GetArrayLength(paths);
    if (count == 0) {
        mark_failed_with_errno(env, "No paths given to watch.", result);
        return NULL;
    }

    watch_details_t* details = (watch_details_t*) malloc(sizeof(watch_details_t));
    details->rootsToWatch = rootsToWatch;
    for (int i = 0; i < count; i++) {
        jstring path = (jstring) env->GetObjectArrayElement(paths, i);
        char* watchedPath = java_to_char(env, path, result);
        printf("~~~~ Watching %s\n", watchedPath);
        if (watchedPath == NULL) {
            mark_failed_with_errno(env, "Could not allocate string to store root to watch.", result);
            freeDetails(env, details);
            return NULL;
        }
        CFStringRef stringPath = CFStringCreateWithCString(NULL, watchedPath, kCFStringEncodingUTF8);
        free(watchedPath);
        if (stringPath == NULL) {
            mark_failed_with_errno(env, "Could not create CFStringRef.", result);
            freeDetails(env, details);
            return NULL;
        }
        CFArrayAppendValue(rootsToWatch, stringPath);
    }

    details->watcherCallback = env->NewGlobalRef(javaCallback);
    if (details->watcherCallback == NULL) {
        mark_failed_with_errno(env, "Could not create global reference for callback.", result);
        freeDetails(env, details);
        return NULL;
    }

    FSEventStreamContext context = {0, (void*) details, NULL, NULL, NULL};
    details->watcherStream = FSEventStreamCreate (
                NULL,
                &callback,
                &context,
                rootsToWatch,
                kFSEventStreamEventIdSinceNow,
                latencyInMillis / 1000.0,
                kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents);
    if (details->watcherStream == NULL) {
        mark_failed_with_errno(env, "Could not create FSEventStreamCreate to track changes.", result);
        freeDetails(env, details);
        return NULL;
    }

    if (pthread_create(&(details->watcherThread), NULL, EventProcessingThread, details) != 0) {
        mark_failed_with_errno(env, "Could not create file watcher thread.", result);
        freeDetails(env, details);
        return NULL;
    }

    // TODO Should this be somewhere global?
    int jvmStatus = env->GetJavaVM(&jvm);
    if (jvmStatus < 0) {
        mark_failed_with_errno(env, "Could not store jvm instance.", result);
        freeDetails(env, details);
        return NULL;
    }

    jclass clsWatcher = env->FindClass("net/rubygrapefruit/platform/internal/jni/OsxFileEventFunctions$WatcherImpl");
    jmethodID constructor = env->GetMethodID(clsWatcher, "<init>", "(Ljava/lang/Object;)V");
    return env->NewObject(clsWatcher, constructor, env->NewDirectByteBuffer(details, sizeof(details)));
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_OsxFileEventFunctions_stopWatching(JNIEnv *env, jclass target, jobject detailsObj, jobject result) {
    watch_details_t *details = (watch_details_t*) env->GetDirectBufferAddress(detailsObj);

    if (invalidStateDetected) {
        // report and reset flag, but try to clean up state as much as possible
        mark_failed_with_errno(env, "Watcher is in invalid state, reported changes may be incorrect.", result);
    }

    freeDetails(env, details);
}

#endif
<|endoftext|>


<commit_before>// RUN: mkdir -p %t
// RUN: %clang_cc1 -x c++ -emit-module -o %t/left.pcm %s -D MODULE_LEFT
// RUN: %clang_cc1 -x c++ -emit-module -o %t/right.pcm %s -D MODULE_RIGHT
// RUN: %clang_cc1 -fmodule-cache-path %t %s -verify

#if defined(MODULE_LEFT)

__module_private__ struct HiddenStruct;

struct HiddenStruct {
};

int &f0(int);

template<typename T>
__module_private__ void f1(T*);

template<typename T>
void f1(T*);

template<typename T>
__module_private__ class vector;

template<typename T>
class vector {
};

vector<float> vec_float;

typedef __module_private__ int Integer;
typedef int Integer;

#elif defined(MODULE_RIGHT)
__module_private__ double &f0(double);
double &f0(double);

__module_private__ int hidden_var;

inline void test_f0_in_right() {
  double &dr = f0(hidden_var);
}

struct VisibleStruct {
  __module_private__ int field;
  __module_private__ void setField(int f);
};

#else
__import_module__ left;
__import_module__ right;

void test() {
  int &ir = f0(1.0); // okay: f0() from 'right' is not visible
}

int test_broken() {
  HiddenStruct hidden; // expected-error{{use of undeclared identifier 'HiddenStruct'}}

  Integer i; // expected-error{{use of undeclared identifier 'Integer'}}

  int *ip = 0;
  f1(ip); // expected-error{{use of undeclared identifier 'f1'}}

  vector<int> vec; // expected-error{{use of undeclared identifier 'vector'}} \
  // expected-error{{expected '(' for function-style cast or type construction}} \
  // expected-error{{use of undeclared identifier 'vec'}}

  VisibleStruct vs;
  vs.field = 0; // expected-error{{no member named 'field' in 'VisibleStruct'}}
  vs.setField(1); // expected-error{{no member named 'setField' in 'VisibleStruct'}}

  return hidden_var; // expected-error{{use of undeclared identifier 'hidden_var'}}
}

// Check for private redeclarations of public entities.
template<typename T>
class public_class_template; // expected-note{{previous declaration is here}}

template<typename T>
__module_private__ class public_class_template; // expected-error{{__module_private__ declaration of 'public_class_template' follows public declaration}}

typedef int public_typedef; // expected-note{{previous declaration is here}}
typedef __module_private__ int public_typedef; // expected-error{{__module_private__ declaration of 'public_typedef' follows public declaration}}

extern int public_var; // expected-note{{previous declaration is here}}
extern __module_private__ int public_var; // expected-error{{__module_private__ declaration of 'public_var' follows public declaration}}

void public_func(); // expected-note{{previous declaration is here}}
__module_private__ void public_func(); // expected-error{{__module_private__ declaration of 'public_func' follows public declaration}}

template<typename T>
void public_func_template(); // expected-note{{previous declaration is here}}
template<typename T>
__module_private__ void public_func_template(); // expected-error{{__module_private__ declaration of 'public_func_template' follows public declaration}}

struct public_struct; // expected-note{{previous declaration is here}}
__module_private__ struct public_struct; // expected-error{{__module_private__ declaration of 'public_struct' follows public declaration}}

// Check for attempts to make specializations private
template<> __module_private__ void public_func_template<int>(); // expected-error{{template specialization cannot be declared __module_private__}}

template<typename T>
struct public_class {
  struct inner_struct;
  static int static_var;

  friend __module_private__ void public_func_friend();
  friend __module_private__ struct public_struct_friend;
};

template<> __module_private__ struct public_class<int>::inner_struct { }; // expected-error{{member specialization cannot be declared __module_private__}}
template<> __module_private__ int public_class<int>::static_var = 17; // expected-error{{member specialization cannot be declared __module_private__}}

template<>
__module_private__ struct public_class<float> { }; // expected-error{{template specialization cannot be declared __module_private__}}

template<typename T>
__module_private__ struct public_class<T *> { }; // expected-error{{partial specialization cannot be declared __module_private__}}

// Check for attempts to make parameters and variables with automatic
// storage module-private.

void local_var_private(__module_private__ int param) { // expected-error{{parameter 'param' cannot be declared __module_private__}}
  __module_private__ struct Local { int x, y; } local; //expected-error{{local variable 'local' cannot be declared __module_private__}}

  __module_private__ struct OtherLocal { int x; }; // expected-error{{local struct cannot be declared __module_private__}}

  typedef __module_private__ int local_typedef; // expected-error{{typedef 'local_typedef' cannot be declared __module_private__}}
}
#endif
<commit_msg>Add a struct-size check for modules when dealing with module-private fields<commit_after>// RUN: mkdir -p %t
// RUN: %clang_cc1 -x c++ -emit-module -o %t/left.pcm %s -D MODULE_LEFT
// RUN: %clang_cc1 -x c++ -emit-module -o %t/right.pcm %s -D MODULE_RIGHT
// RUN: %clang_cc1 -fmodule-cache-path %t %s -verify

#if defined(MODULE_LEFT)

__module_private__ struct HiddenStruct;

struct HiddenStruct {
};

int &f0(int);

template<typename T>
__module_private__ void f1(T*);

template<typename T>
void f1(T*);

template<typename T>
__module_private__ class vector;

template<typename T>
class vector {
};

vector<float> vec_float;

typedef __module_private__ int Integer;
typedef int Integer;

#elif defined(MODULE_RIGHT)
__module_private__ double &f0(double);
double &f0(double);

__module_private__ int hidden_var;

inline void test_f0_in_right() {
  double &dr = f0(hidden_var);
}

struct VisibleStruct {
  __module_private__ int field;
  __module_private__ virtual void setField(int f);
};

#else
__import_module__ left;
__import_module__ right;

void test() {
  int &ir = f0(1.0); // okay: f0() from 'right' is not visible
}

int test_broken() {
  HiddenStruct hidden; // expected-error{{use of undeclared identifier 'HiddenStruct'}}

  Integer i; // expected-error{{use of undeclared identifier 'Integer'}}

  int *ip = 0;
  f1(ip); // expected-error{{use of undeclared identifier 'f1'}}

  vector<int> vec; // expected-error{{use of undeclared identifier 'vector'}} \
  // expected-error{{expected '(' for function-style cast or type construction}} \
  // expected-error{{use of undeclared identifier 'vec'}}

  VisibleStruct vs;
  vs.field = 0; // expected-error{{no member named 'field' in 'VisibleStruct'}}
  vs.setField(1); // expected-error{{no member named 'setField' in 'VisibleStruct'}}

  return hidden_var; // expected-error{{use of undeclared identifier 'hidden_var'}}
}

// Check for private redeclarations of public entities.
template<typename T>
class public_class_template; // expected-note{{previous declaration is here}}

template<typename T>
__module_private__ class public_class_template; // expected-error{{__module_private__ declaration of 'public_class_template' follows public declaration}}

typedef int public_typedef; // expected-note{{previous declaration is here}}
typedef __module_private__ int public_typedef; // expected-error{{__module_private__ declaration of 'public_typedef' follows public declaration}}

extern int public_var; // expected-note{{previous declaration is here}}
extern __module_private__ int public_var; // expected-error{{__module_private__ declaration of 'public_var' follows public declaration}}

void public_func(); // expected-note{{previous declaration is here}}
__module_private__ void public_func(); // expected-error{{__module_private__ declaration of 'public_func' follows public declaration}}

template<typename T>
void public_func_template(); // expected-note{{previous declaration is here}}
template<typename T>
__module_private__ void public_func_template(); // expected-error{{__module_private__ declaration of 'public_func_template' follows public declaration}}

struct public_struct; // expected-note{{previous declaration is here}}
__module_private__ struct public_struct; // expected-error{{__module_private__ declaration of 'public_struct' follows public declaration}}

// Check for attempts to make specializations private
template<> __module_private__ void public_func_template<int>(); // expected-error{{template specialization cannot be declared __module_private__}}

template<typename T>
struct public_class {
  struct inner_struct;
  static int static_var;

  friend __module_private__ void public_func_friend();
  friend __module_private__ struct public_struct_friend;
};

template<> __module_private__ struct public_class<int>::inner_struct { }; // expected-error{{member specialization cannot be declared __module_private__}}
template<> __module_private__ int public_class<int>::static_var = 17; // expected-error{{member specialization cannot be declared __module_private__}}

template<>
__module_private__ struct public_class<float> { }; // expected-error{{template specialization cannot be declared __module_private__}}

template<typename T>
__module_private__ struct public_class<T *> { }; // expected-error{{partial specialization cannot be declared __module_private__}}

// Check for attempts to make parameters and variables with automatic
// storage module-private.

void local_var_private(__module_private__ int param) { // expected-error{{parameter 'param' cannot be declared __module_private__}}
  __module_private__ struct Local { int x, y; } local; //expected-error{{local variable 'local' cannot be declared __module_private__}}

  __module_private__ struct OtherLocal { int x; }; // expected-error{{local struct cannot be declared __module_private__}}

  typedef __module_private__ int local_typedef; // expected-error{{typedef 'local_typedef' cannot be declared __module_private__}}
}

// Check struct size
struct LikeVisibleStruct {
  int field;
  virtual void setField(int f);
};

int check_struct_size[sizeof(VisibleStruct) == sizeof(LikeVisibleStruct)? 1 : -1];
#endif
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2005 Peter Kmmel
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The authors make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include "loki/SmallObj.h"
#include "loki/Function.h"

using namespace Loki;

////////////////////////////////////////////////////////////////////////////////////
//
//    Data object for all singletons
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class T, int Nr>
struct SingletonDataObject
{
    SingletonDataObject() {std::cout<<"new SingletonDataObject"<<Nr<<"\n\n";}
    ~SingletonDataObject(){std::cout<<"delete SingletonDataObject"<<Nr<<"\n\n";}

    int i[Nr];
};

////////////////////////////////////////////////////////////////////////////////////
//
//    How to use LongevityLifetime policies
//    DieAsSmallObjectParent/DieAsSmallObjectChild with SmallObjects?
//
////////////////////////////////////////////////////////////////////////////////////

//  LongevityLifetime::DieAsSmallObjectParent is the default
//  lifetime of SmallObject template:
typedef Loki::SmallObject<>
SmallObject_DieAs;

class MySmallObject_DieAs : public SmallObject_DieAs
{};

typedef SingletonHolder
<
    MySmallObject_DieAs,
    CreateUsingNew,
    LongevityLifetime::DieAsSmallObjectChild
>
Singleton_with_MySmallObject_DieAs;

////////////////////////////////////////////////////////////////////////////////////
//
//    How to use LongevityLifetime policies
//    DieAsSmallObjectParent/DieAsSmallObjectChild with
//    classes containing a Functor/Function?
//
////////////////////////////////////////////////////////////////////////////////////

struct MyFunctionObject_DieAs
{
    MyFunctionObject_DieAs()
    {
        functor  = Functor<void>    (this, &MyFunctionObject_DieAs::f);
        function = Function< void()>(this, &MyFunctionObject_DieAs::f);
    }

    void f(){}
    Functor<void> functor;
    Function<void()> function;

};

typedef SingletonHolder
<
    MyFunctionObject_DieAs,
    CreateUsingNew,
    LongevityLifetime::DieAsSmallObjectChild
>
Singleton_MyFunctionObject_DieAs;

////////////////////////////////////////////////////////////////////////////////////
//
//    Test code for LongevityLifetime Policy
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class Lifetime>
struct Master_die_first
{
    Master_die_first()
    {
        data = &Singleton::Instance();
    }

    virtual ~Master_die_first(){}

    typedef Master_die_first<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,888> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

template<template <class> class Lifetime>
struct Master_die_last
{
    Master_die_last()
    {
        data = &Singleton::Instance();
    }

    virtual ~Master_die_last(){}

    typedef Master_die_last<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,555> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

typedef Master_die_first<LongevityLifetime::DieFirst>
Master1_die_first;

typedef Master_die_last<LongevityLifetime::DieLast>
Master1_die_last;

class B1_die_first;
class B1_die_last;

typedef SingletonHolder<B1_die_first,CreateUsingNew,
LongevityLifetime::DieFirst
> Follower1_Singleton_B1_die_first;

typedef SingletonHolder<B1_die_last,CreateUsingNew,
LongevityLifetime::DieLast
> Follower1_Singleton_B1_die_last;

class B1_die_first : public Master1_die_last
{
public:
    B1_die_first(){std::cout<<"new B1_die_first, look for SingletonDataObject555\n\n";}
    ~B1_die_first(){std::cout<<"delete B1_die_first, look for SingletonDataObject555\n\n";}
};

class B1_die_last : public Master1_die_first
{
public:
    B1_die_last(){std::cout<<"new B1_die_last,  look for SingletonDataObject888\n\n";}
    ~B1_die_last(){std::cout<<"delete B1_die_last,  look for SingletonDataObject888\n\n";}
};

#if !defined(_MSC_VER) || (_MSC_VER>=1400)

////////////////////////////////////////////////////////////////////////////////////
//
//    How to use FollowIntoDeath with SmallObjects?
//
////////////////////////////////////////////////////////////////////////////////////

typedef Loki::SmallObject
<
    LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
    LOKI_DEFAULT_CHUNK_SIZE,
    LOKI_MAX_SMALL_OBJECT_SIZE,
    LOKI_DEFAULT_OBJECT_ALIGNMENT,
    FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime
>
MySmallObjectBase;

struct MySmallObject : public MySmallObjectBase
{
};

typedef SingletonHolder
<
    MySmallObject,
    CreateUsingNew,
    FollowIntoDeath::AfterMaster<MySmallObjectBase::ObjAllocatorSingleton>::IsDestroyed
>
Singleton_of_with_a_MySmallObject;

////////////////////////////////////////////////////////////////////////////////////
//
//    How to use FollowIntoDeath with classes containing a Functor/Function?
//
////////////////////////////////////////////////////////////////////////////////////

struct MyFunctionObject
{
    MyFunctionObject()
    {
        functor  = Functor<void>    (this, &MyFunctionObject::f);
        function = Function< void()>(this, &MyFunctionObject::f);
    }

    void f(){}
    Functor<void> functor;
    Function<void()> function;

};

typedef SingletonHolder
<
    MyFunctionObject,
    CreateUsingNew,
    FollowIntoDeath::AfterMaster<Function<>::Impl::ObjAllocatorSingleton>::IsDestroyed
>
Singleton_MyFunctionObject1;

typedef SingletonHolder
<
    MyFunctionObject,
    CreateUsingNew,
    FollowIntoDeath::AfterMaster<Functor<>::Impl::ObjAllocatorSingleton>::IsDestroyed
>
Singleton_MyFunctionObject2;

////////////////////////////////////////////////////////////////////////////////////
//
//    Test code for FollowIntoDeath policy
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class Lifetime>
struct Master1
{
    Master1()
    {
        data = &Singleton::Instance();
    }

    virtual ~Master1(){}

    typedef Master1<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,1> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

typedef Master1<FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime>
Master1_DefaultLifetime;

typedef Master1<FollowIntoDeath::With<NoDestroy>::AsMasterLifetime>
Master1_NoDestroy;

typedef Master1<FollowIntoDeath::With<PhoenixSingleton>::AsMasterLifetime>
Master1_PhoenixSingleton;

typedef Master1<FollowIntoDeath::With<DeletableSingleton>::AsMasterLifetime>
Master1_DeletableSingleton;

class B1_DefaultLifetime : public Master1_DefaultLifetime
{
public:
    B1_DefaultLifetime(){std::cout<<"new B1_DefaultLifetime\n";}
    ~B1_DefaultLifetime(){std::cout<<"delete B1_DefaultLifetime\n";}
};

class B1_NoDestroy : public Master1_NoDestroy
{
public:
    B1_NoDestroy(){std::cout<<"new B1_NoDestroy. B1_NoDestroy must not be deleted\n";}
    ~B1_NoDestroy(){std::cout<<"delete B1_NoDestroy\n";};
};

class B1_PhoenixSingleton : public Master1_PhoenixSingleton
{
public:
    B1_PhoenixSingleton(){std::cout<<"new B1_PhoenixSingleton\n";}
    ~B1_PhoenixSingleton(){std::cout<<"delete B1_PhoenixSingleton\n";}
};

class B1_DeletableSingleton : public Master1_DeletableSingleton
{
public:
    B1_DeletableSingleton(){std::cout<<"new B1_DeletableSingleton\n";}
    ~B1_DeletableSingleton(){std::cout<<"delete B1_DeletableSingleton\n";}
};

typedef SingletonHolder<B1_DefaultLifetime,CreateUsingNew,
FollowIntoDeath::AfterMaster<Master1_DefaultLifetime::MasterSingleton>::IsDestroyed
> Follower1_Singleton_DefaultLifetime;

typedef SingletonHolder<B1_NoDestroy,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master1_NoDestroy::MasterSingleton>::IsDestroyed
> Follower1_Singleton_NoDestroy;

typedef SingletonHolder<B1_PhoenixSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master1_PhoenixSingleton::MasterSingleton>::IsDestroyed
> Follower1_Singleton_PhoenixSingleton;

typedef SingletonHolder<B1_DeletableSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master1_DeletableSingleton::MasterSingleton>::IsDestroyed
> Follower1_Singleton_DeletableSingleton;

////////////////////////////////////////////////////////////////////////////////////
//
//    Test code for FollowIntoDeath policy with reverse instantiation
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class Lifetime>
struct Master2
{
    Master2()
    {
        // don't create a MasterSingleton2 object!!
        // to test the FollowIntoDeath policy
    }

    virtual ~Master2(){}

    typedef Master2<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,2> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

typedef Master2<FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime>
Master2_DefaultLifetime;

typedef Master2<FollowIntoDeath::With<NoDestroy>::AsMasterLifetime>
Master2_NoDestroy;

typedef Master2<FollowIntoDeath::With<PhoenixSingleton>::AsMasterLifetime>
Master2_PhoenixSingleton;

typedef Master2<FollowIntoDeath::With<DeletableSingleton>::AsMasterLifetime>
Master2_DeletableSingleton;

class B2_DefaultLifetime : public Master2_DefaultLifetime
{
public:
    B2_DefaultLifetime(){std::cout<<"new B2_DefaultLifetime\n";}
    ~B2_DefaultLifetime(){std::cout<<"delete B2_DefaultLifetime\n";}
};

class B2_NoDestroy : public Master2_NoDestroy
{
public:
    B2_NoDestroy(){std::cout<<"new B2_NoDestroy. B2_NoDestroy must not be deleted\n";}
    ~B2_NoDestroy(){std::cout<<"delete B2_NoDestroy\n";};
};

class B2_PhoenixSingleton : public Master2_PhoenixSingleton
{
public:
    B2_PhoenixSingleton(){std::cout<<"new B2_PhoenixSingleton\n";}
    ~B2_PhoenixSingleton(){std::cout<<"delete B2_PhoenixSingleton\n";}
};

class B2_DeletableSingleton : public Master2_DeletableSingleton
{
public:
    B2_DeletableSingleton(){std::cout<<"new B2_DeletableSingleton\n";}
    ~B2_DeletableSingleton(){std::cout<<"delete B2_DeletableSingleton\n";}
};

typedef SingletonHolder<B2_DefaultLifetime,CreateUsingNew,
FollowIntoDeath::AfterMaster<Master2_DefaultLifetime::MasterSingleton>::IsDestroyed
> Follower2_Singleton_DefaultLifetime;

typedef SingletonHolder<B2_NoDestroy,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master2_NoDestroy::MasterSingleton>::IsDestroyed
> Follower2_Singleton_NoDestroy;

typedef SingletonHolder<B2_PhoenixSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master2_PhoenixSingleton::MasterSingleton>::IsDestroyed
> Follower2_Singleton_PhoenixSingleton;

typedef SingletonHolder<B2_DeletableSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master2_DeletableSingleton::MasterSingleton>::IsDestroyed
> Follower2_Singleton_DeletableSingleton;

#endif //#if !defined(_MSC_VER) || (_MSC_VER>=1400)

////////////////////////////////////////////////////////////////////////////////////
//
//    detect memory leaks on MSVC Ide
//
////////////////////////////////////////////////////////////////////////////////////

#ifdef _MSC_VER

#include <crtdbg.h>
#include <cassert>

void heap_debug()
{
    int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );

    // Turn on leak-checking bit
    tmpFlag |= _CRTDBG_LEAK_CHECK_DF;

    //tmpFlag |= _CRTDBG_CHECK_MasterLWMasterYS_DF;

    // Turn off CRT block checking bit
    tmpFlag &= ~_CRTDBG_CHECK_CRT_DF;

    // Set flag to the new value
    _CrtSetDbgFlag( tmpFlag );

}
#endif

////////////////////////////////////////////////////////////////////////////////////
//
//    main
//
////////////////////////////////////////////////////////////////////////////////////

int main(int argc, char *argv[])
{

#ifdef _MSC_VER
    heap_debug();
#endif

    MySmallObject_DieAs    *s_DieAs = &Singleton_with_MySmallObject_DieAs::Instance();
    MyFunctionObject_DieAs *f_DieAs = &Singleton_MyFunctionObject_DieAs::Instance();

    std::cout<<"\n";

    B1_die_first     *first= &Follower1_Singleton_B1_die_first::Instance();
    B1_die_last         *last = &Follower1_Singleton_B1_die_last::Instance();

    // test of FollowIntoDeath policy, not supported by msvc 7.1 compiler
#if !defined(_MSC_VER) || (_MSC_VER>=1400)

    MyFunctionObject *f1 = &Singleton_MyFunctionObject1::Instance();
    MyFunctionObject *f2 = &Singleton_MyFunctionObject2::Instance();

    std::cout << "\nMaster1:\n\n";

    B1_DefaultLifetime     *def = &Follower1_Singleton_DefaultLifetime::Instance();
    B1_PhoenixSingleton     *pho = &Follower1_Singleton_PhoenixSingleton::Instance();
    B1_DeletableSingleton *del = &Follower1_Singleton_DeletableSingleton::Instance();

    std::cout << "\n\nMaster2:\n\n";

    B2_DefaultLifetime     *def2 = &Follower2_Singleton_DefaultLifetime::Instance();
    def2->data = &Master2_DefaultLifetime::Singleton::Instance();

    B2_PhoenixSingleton     *pho2 = &Follower2_Singleton_PhoenixSingleton::Instance();
    pho2->data = &Master2_PhoenixSingleton::Singleton::Instance();

    B2_DeletableSingleton *del2 = &Follower2_Singleton_DeletableSingleton::Instance();
    del2->data = &Master2_DeletableSingleton::Singleton::Instance();

    // memory leak when code is enabled
    //#define ENMasterBLE_LEMasterK
#ifdef ENMasterBLE_LEMasterK
    B1_NoDestroy          *no = &Follower1_Singleton_NoDestroy::Instance();
    B2_NoDestroy          *no2 = &Follower2_Singleton_NoDestro0::Instance();
    no2->data = &Master2_NoDestroy::Singleton::Instance();
#endif

#endif //#if !defined(_MSC_VER) || (_MSC_VER>=1400)

#if defined(__BORLANDC__) || defined(__GNUC__) || defined(_MSC_VER)
    system("pause"); // Stop console window from closing if run from IDE.
#endif

    std::cout << "\nnow leaving main \n";
    std::cout << "________________________________\n\n";

    return 0;
}
<commit_msg>remove warnings and adjust code to new default lifetimes of SmallObjects<commit_after>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2005 Peter Kmmel
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The authors make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include "loki/SmallObj.h"
#include "loki/Function.h"

using namespace Loki;

////////////////////////////////////////////////////////////////////////////////////
//
//    Data object for all singletons
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class T, int Nr>
struct SingletonDataObject
{
    SingletonDataObject() {std::cout<<"new SingletonDataObject"<<Nr<<"\n\n";}
    ~SingletonDataObject(){std::cout<<"delete SingletonDataObject"<<Nr<<"\n\n";}

    int i[Nr];
};

////////////////////////////////////////////////////////////////////////////////////
//
//    How to use LongevityLifetime policies
//    DieAsSmallObjectParent/DieAsSmallObjectChild with SmallObjects?
//
////////////////////////////////////////////////////////////////////////////////////

//  LongevityLifetime::DieAsSmallObjectParent is the default lifetime
//  of SmallObject template:
typedef Loki::SmallObject<>
SmallObject_DieAs;

class MySmallObject_DieAs : public SmallObject_DieAs
{};

typedef SingletonHolder
<
    MySmallObject_DieAs,
    CreateUsingNew,
    LongevityLifetime::DieAsSmallObjectChild
>
Singleton_with_MySmallObject_DieAs;

////////////////////////////////////////////////////////////////////////////////////
//
//    How to use LongevityLifetime policies
//    DieAsSmallObjectParent/DieAsSmallObjectChild with
//    classes containing a Functor/Function?
//
////////////////////////////////////////////////////////////////////////////////////

struct MyFunctionObject_DieAs
{
    MyFunctionObject_DieAs()
    {
        functor  = Functor<void>    (this, &MyFunctionObject_DieAs::f);
        function = Function< void()>(this, &MyFunctionObject_DieAs::f);
    }

    void f(){}
    Functor<void> functor;
    Function<void()> function;

};

typedef SingletonHolder
<
    MyFunctionObject_DieAs,
    CreateUsingNew,
    LongevityLifetime::DieAsSmallObjectChild
>
Singleton_MyFunctionObject_DieAs;

////////////////////////////////////////////////////////////////////////////////////
//
//    Test code for LongevityLifetime Policy
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class Lifetime>
struct Master_die_first
{
    Master_die_first()
    {
        data = &Singleton::Instance();
    }

    virtual ~Master_die_first(){}

    typedef Master_die_first<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,888> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

template<template <class> class Lifetime>
struct Master_die_last
{
    Master_die_last()
    {
        data = &Singleton::Instance();
    }

    virtual ~Master_die_last(){}

    typedef Master_die_last<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,555> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

typedef Master_die_first<LongevityLifetime::DieFirst>
Master1_die_first;

typedef Master_die_last<LongevityLifetime::DieLast>
Master1_die_last;

class B1_die_first;
class B1_die_last;

typedef SingletonHolder<B1_die_first,CreateUsingNew,
LongevityLifetime::DieFirst
> Follower1_Singleton_B1_die_first;

typedef SingletonHolder<B1_die_last,CreateUsingNew,
LongevityLifetime::DieLast
> Follower1_Singleton_B1_die_last;

class B1_die_first : public Master1_die_last
{
public:
    B1_die_first(){std::cout<<"new B1_die_first, look for SingletonDataObject555\n\n";}
    ~B1_die_first(){std::cout<<"delete B1_die_first, look for SingletonDataObject555\n\n";}
};

class B1_die_last : public Master1_die_first
{
public:
    B1_die_last(){std::cout<<"new B1_die_last,  look for SingletonDataObject888\n\n";}
    ~B1_die_last(){std::cout<<"delete B1_die_last,  look for SingletonDataObject888\n\n";}
};

// test of FollowIntoDeath policy, not supported by msvc 7.1 compiler
#if !defined(_MSC_VER) || (_MSC_VER>=1400)

////////////////////////////////////////////////////////////////////////////////////
//
//    How to use FollowIntoDeath with SmallObjects?
//
////////////////////////////////////////////////////////////////////////////////////

typedef Loki::SmallObject
<
    LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
    LOKI_DEFAULT_CHUNK_SIZE,
    LOKI_MAX_SMALL_OBJECT_SIZE,
    LOKI_DEFAULT_OBJECT_ALIGNMENT,
    FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime
>
MySmallObjectBase;

struct MySmallObject : public MySmallObjectBase
{
};

typedef SingletonHolder
<
    MySmallObject,
    CreateUsingNew,
    FollowIntoDeath::AfterMaster<MySmallObjectBase::ObjAllocatorSingleton>::IsDestroyed
>
Singleton_of_with_a_MySmallObject;

////////////////////////////////////////////////////////////////////////////////////
//
//    Test code for FollowIntoDeath policy
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class Lifetime>
struct Master1
{
    Master1()
    {
        data = &Singleton::Instance();
    }

    virtual ~Master1(){}

    typedef Master1<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,1> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

typedef Master1<FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime>
Master1_DefaultLifetime;

typedef Master1<FollowIntoDeath::With<NoDestroy>::AsMasterLifetime>
Master1_NoDestroy;

typedef Master1<FollowIntoDeath::With<PhoenixSingleton>::AsMasterLifetime>
Master1_PhoenixSingleton;

typedef Master1<FollowIntoDeath::With<DeletableSingleton>::AsMasterLifetime>
Master1_DeletableSingleton;

class B1_DefaultLifetime : public Master1_DefaultLifetime
{
public:
    B1_DefaultLifetime(){std::cout<<"new B1_DefaultLifetime\n";}
    ~B1_DefaultLifetime(){std::cout<<"delete B1_DefaultLifetime\n";}
};

class B1_NoDestroy : public Master1_NoDestroy
{
public:
    B1_NoDestroy(){std::cout<<"new B1_NoDestroy. B1_NoDestroy must not be deleted\n";}
    ~B1_NoDestroy(){std::cout<<"delete B1_NoDestroy\n";};
};

class B1_PhoenixSingleton : public Master1_PhoenixSingleton
{
public:
    B1_PhoenixSingleton(){std::cout<<"new B1_PhoenixSingleton\n";}
    ~B1_PhoenixSingleton(){std::cout<<"delete B1_PhoenixSingleton\n";}
};

class B1_DeletableSingleton : public Master1_DeletableSingleton
{
public:
    B1_DeletableSingleton(){std::cout<<"new B1_DeletableSingleton\n";}
    ~B1_DeletableSingleton(){std::cout<<"delete B1_DeletableSingleton\n";}
};

typedef SingletonHolder<B1_DefaultLifetime,CreateUsingNew,
FollowIntoDeath::AfterMaster<Master1_DefaultLifetime::MasterSingleton>::IsDestroyed
> Follower1_Singleton_DefaultLifetime;

typedef SingletonHolder<B1_NoDestroy,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master1_NoDestroy::MasterSingleton>::IsDestroyed
> Follower1_Singleton_NoDestroy;

typedef SingletonHolder<B1_PhoenixSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master1_PhoenixSingleton::MasterSingleton>::IsDestroyed
> Follower1_Singleton_PhoenixSingleton;

typedef SingletonHolder<B1_DeletableSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master1_DeletableSingleton::MasterSingleton>::IsDestroyed
> Follower1_Singleton_DeletableSingleton;

////////////////////////////////////////////////////////////////////////////////////
//
//    Test code for FollowIntoDeath policy with reverse instantiation
//
////////////////////////////////////////////////////////////////////////////////////

template<template <class> class Lifetime>
struct Master2
{
    Master2()
    {
        // don't create a MasterSingleton2 object!!
        // to test the FollowIntoDeath policy
    }

    virtual ~Master2(){}

    typedef Master2<Lifetime> ThisType;
    typedef SingletonDataObject<Lifetime,2> MasterSingleton;
    typedef SingletonHolder<MasterSingleton,CreateUsingNew,Lifetime> Singleton;

    MasterSingleton* data;
};

typedef Master2<FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime>
Master2_DefaultLifetime;

typedef Master2<FollowIntoDeath::With<NoDestroy>::AsMasterLifetime>
Master2_NoDestroy;

typedef Master2<FollowIntoDeath::With<PhoenixSingleton>::AsMasterLifetime>
Master2_PhoenixSingleton;

typedef Master2<FollowIntoDeath::With<DeletableSingleton>::AsMasterLifetime>
Master2_DeletableSingleton;

class B2_DefaultLifetime : public Master2_DefaultLifetime
{
public:
    B2_DefaultLifetime(){std::cout<<"new B2_DefaultLifetime\n";}
    ~B2_DefaultLifetime(){std::cout<<"delete B2_DefaultLifetime\n";}
};

class B2_NoDestroy : public Master2_NoDestroy
{
public:
    B2_NoDestroy(){std::cout<<"new B2_NoDestroy. B2_NoDestroy must not be deleted\n";}
    ~B2_NoDestroy(){std::cout<<"delete B2_NoDestroy\n";};
};

class B2_PhoenixSingleton : public Master2_PhoenixSingleton
{
public:
    B2_PhoenixSingleton(){std::cout<<"new B2_PhoenixSingleton\n";}
    ~B2_PhoenixSingleton(){std::cout<<"delete B2_PhoenixSingleton\n";}
};

class B2_DeletableSingleton : public Master2_DeletableSingleton
{
public:
    B2_DeletableSingleton(){std::cout<<"new B2_DeletableSingleton\n";}
    ~B2_DeletableSingleton(){std::cout<<"delete B2_DeletableSingleton\n";}
};

typedef SingletonHolder<B2_DefaultLifetime,CreateUsingNew,
FollowIntoDeath::AfterMaster<Master2_DefaultLifetime::MasterSingleton>::IsDestroyed
> Follower2_Singleton_DefaultLifetime;

typedef SingletonHolder<B2_NoDestroy,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master2_NoDestroy::MasterSingleton>::IsDestroyed
> Follower2_Singleton_NoDestroy;

typedef SingletonHolder<B2_PhoenixSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master2_PhoenixSingleton::MasterSingleton>::IsDestroyed
> Follower2_Singleton_PhoenixSingleton;

typedef SingletonHolder<B2_DeletableSingleton,CreateUsingNew,
    FollowIntoDeath::AfterMaster<Master2_DeletableSingleton::MasterSingleton>::IsDestroyed
> Follower2_Singleton_DeletableSingleton;

#endif //#if !defined(_MSC_VER) || (_MSC_VER>=1400)

////////////////////////////////////////////////////////////////////////////////////
//
//    detect memory leaks on MSVC Ide
//
////////////////////////////////////////////////////////////////////////////////////

#ifdef _MSC_VER

#include <crtdbg.h>
#include <cassert>

void heap_debug()
{
    int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );

    // Turn on leak-checking bit
    tmpFlag |= _CRTDBG_LEAK_CHECK_DF;

    //tmpFlag |= _CRTDBG_CHECK_MasterLWMasterYS_DF;

    // Turn off CRT block checking bit
    tmpFlag &= ~_CRTDBG_CHECK_CRT_DF;

    // Set flag to the new value
    _CrtSetDbgFlag( tmpFlag );

}
#endif

////////////////////////////////////////////////////////////////////////////////////
//
//    main
//
////////////////////////////////////////////////////////////////////////////////////

int main()
{

#ifdef _MSC_VER
    heap_debug();
#endif

    void* p;

    p = (void*) &Singleton_with_MySmallObject_DieAs::Instance();
    p = (void*) &Singleton_MyFunctionObject_DieAs::Instance();

    std::cout<<"\n";

    p = (void*) &Follower1_Singleton_B1_die_first::Instance();
    p = (void*) &Follower1_Singleton_B1_die_last::Instance();

    // test of FollowIntoDeath policy, not supported by msvc 7.1 compiler
#if !defined(_MSC_VER) || (_MSC_VER>=1400)

    std::cout << "\nMaster1:\n\n";

    p = (void*) &Follower1_Singleton_DefaultLifetime::Instance();
    p = (void*) &Follower1_Singleton_PhoenixSingleton::Instance();
    p = (void*) &Follower1_Singleton_DeletableSingleton::Instance();

    std::cout << "\n\nMaster2:\n\n";

    B2_DefaultLifetime *def2 = &Follower2_Singleton_DefaultLifetime::Instance();
    def2->data = &Master2_DefaultLifetime::Singleton::Instance();

    B2_PhoenixSingleton *pho2 = &Follower2_Singleton_PhoenixSingleton::Instance();
    pho2->data = &Master2_PhoenixSingleton::Singleton::Instance();

    B2_DeletableSingleton *del2 = &Follower2_Singleton_DeletableSingleton::Instance();
    del2->data = &Master2_DeletableSingleton::Singleton::Instance();

    // memory leak when code is enabled
//#define ENABLE_MEMORY_LEAK
#ifdef ENABLE_MEMORY_LEAK
    p = (void*) &Follower1_Singleton_NoDestroy::Instance();
    B2_NoDestroy *no2 = &Follower2_Singleton_NoDestroy::Instance();
    no2->data = &Master2_NoDestroy::Singleton::Instance();
#endif

#endif //#if !defined(_MSC_VER) || (_MSC_VER>=1400)

#if defined(__BORLANDC__) || defined(__GNUC__) || defined(_MSC_VER)
    system("pause");
#endif

    std::cout << "\nnow leaving main \n";
    std::cout << "________________________________\n\n";

    return 0;
}
<|endoftext|>


<commit_before>
//#define LOKI_CLASS_LEVEL_THREADING
//#define LOKI_OBJECT_LEVEL_THREADING

#include "SmallObj.h"
#include "timer.h"

#include <string>

using namespace std;

class ThisIsASmallObject
{
	int i;
	double d;
	//std::string s;
};

template<class T>
struct Base : public ThisIsASmallObject, public T {};
template<>
struct Base<void> : public ThisIsASmallObject {};

typedef Base<void>
A;
typedef Base<Loki::SmallObject<> >
B;
typedef Base<Loki::SmallValueObject<> >
C;

/*
class A
{ int i; int* p;};
class B : public Loki::SmallObject<>
{ int i; int* p;};
class C : public Loki::SmallValueObject<>
{ int i; int* p;};
*/

template<class T>
int run_new_delete(int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
	{
		T* p = new T;
		delete p;
	}
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

template<class T>
int run_new_delete(T** array, int N, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
		for (int n=0; n<N; n++)
		{
			array[n] = new T;
			delete array[n];
		}
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

template<class T>
int run_new(T** array, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
		array[i] = new T;
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}
template<class T>
int run_delete(T** array, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
		delete array[i];
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

template<class T>
int run_new_delete_array(int N, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
	{
		T* p = new T[N];
		delete [] p;
	}
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

int main()
{
	int loop = 1000000
	;

	Timer t;

	t.t100 = 0;
	t.t100 = run_new_delete<A>(loop,t,"new & delete A : ");
	run_new_delete<B>(loop,t,"new & delete B : ");
	run_new_delete<C>(loop,t,"new & delete C : ");

	cout << endl << endl;
//    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	int N = 100000;
	int loop2 = loop/N*10;

	A** a = new A*[N];
	B** b = new B*[N];
	C** c = new C*[N];

	for(int i=0; i<N; i++)
	{
		a[i]=0;
		b[i]=0;
		c[i]=0;
	}

	t.t100 = 0;
	t.t100 = run_new_delete(a,N,loop2,t,"new & delete A on array : ");
	run_new_delete(b,N,loop2,t,"new & delete B on array : ");
	run_new_delete(c,N,loop2,t,"new & delete C on array : ");

	cout << endl << endl;
//    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	t.t100 = 0;
	t.t100 = run_new(a,N,t,"new A on array : ");
	run_new(b,N,t,"new B on array : ");
	run_new(c,N,t,"new C on array : ");

	cout << endl;
////////////////////////////////////////////////////////////////////////////////

	t.t100 = 0;
	t.t100 = run_delete(a,N,t,"delete A on array : ");
	run_delete(b,N,t,"delete B on array : ");
	run_delete(c,N,t,"delete C on array : ");

	delete [] a;
	delete [] b;
	delete [] c;

	cout << endl << endl;
//    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	N = 5;

	t.t100 = 0;
	t.t100 = run_new_delete_array<A>(N,loop,t,"new & delete [] A : ");
	run_new_delete_array<B>(N,loop,t,"new & delete [] B : ");
	run_new_delete_array<C>(N,loop,t,"new & delete [] C : ");

	cout << endl << endl;
    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	cout << endl;
	system("PAUSE");
	return 0;
}

<commit_msg>Added comments saying how to test array forms of new and delete.<commit_after>
//#define LOKI_CLASS_LEVEL_THREADING
//#define LOKI_OBJECT_LEVEL_THREADING

// Uncomment this to test new [] and delete [].
// #define LOKI_SMALL_OBJECT_USE_NEW_ARRAY

#include "SmallObj.h"
#include "timer.h"

#include <string>

using namespace std;

class ThisIsASmallObject
{
	int i;
	double d;
	//std::string s;
};

template<class T>
struct Base : public ThisIsASmallObject, public T {};
template<>
struct Base<void> : public ThisIsASmallObject {};

typedef Base<void>
A;
typedef Base<Loki::SmallObject<> >
B;
typedef Base<Loki::SmallValueObject<> >
C;

/*
class A
{ int i; int* p;};
class B : public Loki::SmallObject<>
{ int i; int* p;};
class C : public Loki::SmallValueObject<>
{ int i; int* p;};
*/

template<class T>
int run_new_delete(int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
	{
		T* p = new T;
		delete p;
	}
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

template<class T>
int run_new_delete(T** array, int N, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
		for (int n=0; n<N; n++)
		{
			array[n] = new T;
			delete array[n];
		}
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

template<class T>
int run_new(T** array, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
		array[i] = new T;
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}
template<class T>
int run_delete(T** array, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
		delete array[i];
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

template<class T>
int run_new_delete_array(int N, int loop, Timer& t, char* s)
{
	t.start();
	/****************************************************************/
	for (int i=0; i<loop; ++i)
	{
		T* p = new T[N];
		delete [] p;
	}
	/****************************************************************/
	t.stop();
	t.print(t.t(),s);
	return t.t();
}

int main()
{
	int loop = 1000000
	;

	Timer t;

	t.t100 = 0;
	t.t100 = run_new_delete<A>(loop,t,"new & delete A : ");
	run_new_delete<B>(loop,t,"new & delete B : ");
	run_new_delete<C>(loop,t,"new & delete C : ");

	cout << endl << endl;
//    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	int N = 100000;
	int loop2 = loop/N*10;

	A** a = new A*[N];
	B** b = new B*[N];
	C** c = new C*[N];

	for(int i=0; i<N; i++)
	{
		a[i]=0;
		b[i]=0;
		c[i]=0;
	}

	t.t100 = 0;
	t.t100 = run_new_delete(a,N,loop2,t,"new & delete A on array : ");
	run_new_delete(b,N,loop2,t,"new & delete B on array : ");
	run_new_delete(c,N,loop2,t,"new & delete C on array : ");

	cout << endl << endl;
//    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	t.t100 = 0;
	t.t100 = run_new(a,N,t,"new A on array : ");
	run_new(b,N,t,"new B on array : ");
	run_new(c,N,t,"new C on array : ");

	cout << endl;
////////////////////////////////////////////////////////////////////////////////

	t.t100 = 0;
	t.t100 = run_delete(a,N,t,"delete A on array : ");
	run_delete(b,N,t,"delete B on array : ");
	run_delete(c,N,t,"delete C on array : ");

	delete [] a;
	delete [] b;
	delete [] c;

	cout << endl << endl;
//    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	N = 5;

	t.t100 = 0;
	t.t100 = run_new_delete_array<A>(N,loop,t,"new & delete [] A : ");
	run_new_delete_array<B>(N,loop,t,"new & delete [] B : ");
	run_new_delete_array<C>(N,loop,t,"new & delete [] C : ");

	cout << endl << endl;
    Loki::AllocatorSingleton<>::ClearExtraMemory();
////////////////////////////////////////////////////////////////////////////////

	cout << endl;
	system("PAUSE");
	return 0;
}

<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief   Adapter implementation that wraps a single std::string value
 *
 * This allows property names to be validated against a schema as though they are a generic JSON
 * value, while allowing the rest of Valijson's API to expose property names as plain std::string
 * values.
 *
 * This was added while implementing draft 7 support. This included support for a constraint
 * called propertyNames, which can be used to ensure that the property names in an object
 * validate against a subschema.
 */

#pragma once

#include <string>

#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>

namespace valijson {
namespace adapters {

class StdStringAdapter;
class StdStringArrayValueIterator;
class StdStringObjectMemberIterator;

typedef std::pair<std::string, StdStringAdapter> StdStringObjectMember;

class StdStringArray
{
public:
    typedef StdStringArrayValueIterator const_iterator;
    typedef StdStringArrayValueIterator iterator;

    StdStringArray() { }

    StdStringArrayValueIterator begin() const;

    StdStringArrayValueIterator end() const;

    size_t size() const
    {
        return 0;
    }
};

class StdStringObject
{
public:
    typedef StdStringObjectMemberIterator const_iterator;
    typedef StdStringObjectMemberIterator iterator;

    StdStringObject() { }

    StdStringObjectMemberIterator begin() const;

    StdStringObjectMemberIterator end() const;

    StdStringObjectMemberIterator find(const std::string &propertyName) const;

    size_t size() const
    {
        return 0;
    }
};

class StdStringFrozenValue: public FrozenValue
{
public:
    explicit StdStringFrozenValue(const std::string &source)
      : value(source) { }

    virtual FrozenValue * clone() const
    {
        return new StdStringFrozenValue(value);
    }

    virtual bool equalTo(const Adapter &other, bool strict) const;

private:
    std::string value;
};

class StdStringAdapter: public Adapter
{
public:
    typedef StdStringArray Array;
    typedef StdStringObject Object;
    typedef StdStringObjectMember ObjectMember;

    StdStringAdapter(const std::string &value)
      : value(value) { }

    virtual bool applyToArray(ArrayValueCallback fn) const
    {
        return maybeArray();
    }

    virtual bool applyToObject(ObjectMemberCallback fn) const
    {
        return maybeObject();
    }

    StdStringArray asArray() const
    {
        if (maybeArray()) {
            return StdStringArray();
        }

        throw std::runtime_error("String value cannot be cast to array");
    }

    virtual bool asBool() const
    {
        return true;
    }

    virtual bool asBool(bool &result) const
    {
        result = true;
        return true;
    }

    virtual double asDouble() const
    {
        return 0;
    }

    virtual bool asDouble(double &result) const
    {
        result = 0;
        return true;
    }

    virtual int64_t asInteger() const
    {
        return 0;
    }

    virtual bool asInteger(int64_t &result) const
    {
        result = 0;
        return true;
    };

    StdStringObject asObject() const
    {
        if (maybeObject()) {
            return StdStringObject();
        }

        throw std::runtime_error("String value cannot be cast to object");
    }

    virtual std::string asString() const
    {
        return value;
    }

    virtual bool asString(std::string &result) const
    {
        result = value;
        return true;
    }

    virtual bool equalTo(const Adapter &other, bool strict) const
    {
        if (strict && !other.isString()) {
            return false;
        }

        return value.compare(other.asString()) == 0;
    }

    virtual FrozenValue* freeze() const
    {
        return new StdStringFrozenValue(value);
    }

    StdStringArray getArray() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual size_t getArraySize() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getArraySize(size_t &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getBool() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getBool(bool &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual double getDouble() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getDouble(double &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual int64_t getInteger() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getInteger(int64_t &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual double getNumber() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getNumber(double &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual size_t getObjectSize() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getObjectSize(size_t &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual std::string getString() const
    {
        return value;
    }

    virtual bool getString(std::string &result) const
    {
        result = value;
        return true;
    }

    virtual bool hasStrictTypes() const
    {
        return true;
    }

    virtual bool isArray() const
    {
        return false;
    }

    virtual bool isBool() const
    {
        return false;
    }

    virtual bool isDouble() const
    {
        return false;
    }

    virtual bool isInteger() const
    {
        return false;
    }

    virtual bool isNull() const
    {
        return false;
    }

    virtual bool isNumber() const
    {
        return false;
    }

    virtual bool isObject() const
    {
        return false;
    }

    virtual bool isString() const
    {
        return true;
    }

    virtual bool maybeArray() const
    {
        return false;
    }

    virtual bool maybeBool() const
    {
        return value.compare("true") == 0 || value.compare("false") == 0;
    }

    virtual bool maybeDouble() const
    {
        const char *b = value.c_str();
        char *e = NULL;
        strtod(b, &e);
        return e != b && e == b + value.length();
    }

    virtual bool maybeInteger() const
    {
        std::istringstream i(value);
        int64_t x;
        char c;
        if (!(i >> x) || i.get(c)) {
            return false;
        }

        return true;
    }

    virtual bool maybeNull() const
    {
        return value.size() == 0;
    }

    virtual bool maybeObject() const
    {
        return value.size() == 0;
    }

    virtual bool maybeString() const
    {
        return true;
    }

private:
    const std::string &value;
};

class StdStringArrayValueIterator:
    public std::iterator<
        std::bidirectional_iterator_tag,
        StdStringAdapter>
{
public:
    StdStringAdapter operator*() const
    {
        throw std::runtime_error("Not supported");
    }

    DerefProxy<StdStringAdapter> operator->() const
    {
        throw std::runtime_error("Not supported");
    }

    bool operator==(const StdStringArrayValueIterator &other) const
    {
        return true;
    }

    bool operator!=(const StdStringArrayValueIterator &other) const
    {
        return false;
    }

    const StdStringArrayValueIterator& operator++()
    {
        throw std::runtime_error("Not supported");
    }

    StdStringArrayValueIterator operator++(int)
    {
        throw std::runtime_error("Not supported");
    }

    const StdStringArrayValueIterator& operator--()
    {
        throw std::runtime_error("Not supported");
    }

    void advance(std::ptrdiff_t n)
    {
        throw std::runtime_error("Not supported");
    }
};

inline StdStringArrayValueIterator StdStringArray::begin() const
{
    return StdStringArrayValueIterator();
}

inline StdStringArrayValueIterator StdStringArray::end() const
{
    return StdStringArrayValueIterator();
}

class StdStringObjectMemberIterator:
    public std::iterator<
        std::bidirectional_iterator_tag,
        StdStringObjectMember>
{
public:
    StdStringObjectMember operator*() const
    {
        throw std::runtime_error("Not supported");
    }

    DerefProxy<StdStringObjectMember> operator->() const
    {
        throw std::runtime_error("Not supported");
    }

    bool operator==(const StdStringObjectMemberIterator &) const
    {
        return true;
    }

    bool operator!=(const StdStringObjectMemberIterator &) const
    {
        return false;
    }

    const StdStringObjectMemberIterator& operator++()
    {
        throw std::runtime_error("Not supported");
    }

    StdStringObjectMemberIterator operator++(int)
    {
        throw std::runtime_error("Not supported");
    }

    const StdStringObjectMemberIterator& operator--()
    {
        throw std::runtime_error("Not supported");
    }
};

inline StdStringObjectMemberIterator StdStringObject::begin() const
{
    return StdStringObjectMemberIterator();
}

inline StdStringObjectMemberIterator StdStringObject::end() const
{
    return StdStringObjectMemberIterator();
}

inline StdStringObjectMemberIterator StdStringObject::find(const std::string &propertyName) const
{
    return StdStringObjectMemberIterator();
}

template<>
struct AdapterTraits<valijson::adapters::StdStringAdapter>
{
    typedef std::string DocumentType;

    static std::string adapterName()
    {
        return "StdStringAdapter";
    }
};

inline bool StdStringFrozenValue::equalTo(const Adapter &other, bool strict) const
{
    return StdStringAdapter(value).equalTo(other, strict);
}

}  // namespace adapters
}  // namespace valijson
<commit_msg>Add missing include for DerefProxy<commit_after>/**
 * @file
 *
 * @brief   Adapter implementation that wraps a single std::string value
 *
 * This allows property names to be validated against a schema as though they are a generic JSON
 * value, while allowing the rest of Valijson's API to expose property names as plain std::string
 * values.
 *
 * This was added while implementing draft 7 support. This included support for a constraint
 * called propertyNames, which can be used to ensure that the property names in an object
 * validate against a subschema.
 */

#pragma once

#include <string>

#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/adapters/basic_adapter.hpp>

namespace valijson {
namespace adapters {

class StdStringAdapter;
class StdStringArrayValueIterator;
class StdStringObjectMemberIterator;

typedef std::pair<std::string, StdStringAdapter> StdStringObjectMember;

class StdStringArray
{
public:
    typedef StdStringArrayValueIterator const_iterator;
    typedef StdStringArrayValueIterator iterator;

    StdStringArray() { }

    StdStringArrayValueIterator begin() const;

    StdStringArrayValueIterator end() const;

    size_t size() const
    {
        return 0;
    }
};

class StdStringObject
{
public:
    typedef StdStringObjectMemberIterator const_iterator;
    typedef StdStringObjectMemberIterator iterator;

    StdStringObject() { }

    StdStringObjectMemberIterator begin() const;

    StdStringObjectMemberIterator end() const;

    StdStringObjectMemberIterator find(const std::string &propertyName) const;

    size_t size() const
    {
        return 0;
    }
};

class StdStringFrozenValue: public FrozenValue
{
public:
    explicit StdStringFrozenValue(const std::string &source)
      : value(source) { }

    virtual FrozenValue * clone() const
    {
        return new StdStringFrozenValue(value);
    }

    virtual bool equalTo(const Adapter &other, bool strict) const;

private:
    std::string value;
};

class StdStringAdapter: public Adapter
{
public:
    typedef StdStringArray Array;
    typedef StdStringObject Object;
    typedef StdStringObjectMember ObjectMember;

    StdStringAdapter(const std::string &value)
      : value(value) { }

    virtual bool applyToArray(ArrayValueCallback fn) const
    {
        return maybeArray();
    }

    virtual bool applyToObject(ObjectMemberCallback fn) const
    {
        return maybeObject();
    }

    StdStringArray asArray() const
    {
        if (maybeArray()) {
            return StdStringArray();
        }

        throw std::runtime_error("String value cannot be cast to array");
    }

    virtual bool asBool() const
    {
        return true;
    }

    virtual bool asBool(bool &result) const
    {
        result = true;
        return true;
    }

    virtual double asDouble() const
    {
        return 0;
    }

    virtual bool asDouble(double &result) const
    {
        result = 0;
        return true;
    }

    virtual int64_t asInteger() const
    {
        return 0;
    }

    virtual bool asInteger(int64_t &result) const
    {
        result = 0;
        return true;
    };

    StdStringObject asObject() const
    {
        if (maybeObject()) {
            return StdStringObject();
        }

        throw std::runtime_error("String value cannot be cast to object");
    }

    virtual std::string asString() const
    {
        return value;
    }

    virtual bool asString(std::string &result) const
    {
        result = value;
        return true;
    }

    virtual bool equalTo(const Adapter &other, bool strict) const
    {
        if (strict && !other.isString()) {
            return false;
        }

        return value.compare(other.asString()) == 0;
    }

    virtual FrozenValue* freeze() const
    {
        return new StdStringFrozenValue(value);
    }

    StdStringArray getArray() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual size_t getArraySize() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getArraySize(size_t &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getBool() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getBool(bool &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual double getDouble() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getDouble(double &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual int64_t getInteger() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getInteger(int64_t &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual double getNumber() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getNumber(double &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual size_t getObjectSize() const
    {
        throw std::runtime_error("Not supported");
    }

    virtual bool getObjectSize(size_t &result) const
    {
        throw std::runtime_error("Not supported");
    }

    virtual std::string getString() const
    {
        return value;
    }

    virtual bool getString(std::string &result) const
    {
        result = value;
        return true;
    }

    virtual bool hasStrictTypes() const
    {
        return true;
    }

    virtual bool isArray() const
    {
        return false;
    }

    virtual bool isBool() const
    {
        return false;
    }

    virtual bool isDouble() const
    {
        return false;
    }

    virtual bool isInteger() const
    {
        return false;
    }

    virtual bool isNull() const
    {
        return false;
    }

    virtual bool isNumber() const
    {
        return false;
    }

    virtual bool isObject() const
    {
        return false;
    }

    virtual bool isString() const
    {
        return true;
    }

    virtual bool maybeArray() const
    {
        return false;
    }

    virtual bool maybeBool() const
    {
        return value.compare("true") == 0 || value.compare("false") == 0;
    }

    virtual bool maybeDouble() const
    {
        const char *b = value.c_str();
        char *e = NULL;
        strtod(b, &e);
        return e != b && e == b + value.length();
    }

    virtual bool maybeInteger() const
    {
        std::istringstream i(value);
        int64_t x;
        char c;
        if (!(i >> x) || i.get(c)) {
            return false;
        }

        return true;
    }

    virtual bool maybeNull() const
    {
        return value.size() == 0;
    }

    virtual bool maybeObject() const
    {
        return value.size() == 0;
    }

    virtual bool maybeString() const
    {
        return true;
    }

private:
    const std::string &value;
};

class StdStringArrayValueIterator:
    public std::iterator<
        std::bidirectional_iterator_tag,
        StdStringAdapter>
{
public:
    StdStringAdapter operator*() const
    {
        throw std::runtime_error("Not supported");
    }

    DerefProxy<StdStringAdapter> operator->() const
    {
        throw std::runtime_error("Not supported");
    }

    bool operator==(const StdStringArrayValueIterator &other) const
    {
        return true;
    }

    bool operator!=(const StdStringArrayValueIterator &other) const
    {
        return false;
    }

    const StdStringArrayValueIterator& operator++()
    {
        throw std::runtime_error("Not supported");
    }

    StdStringArrayValueIterator operator++(int)
    {
        throw std::runtime_error("Not supported");
    }

    const StdStringArrayValueIterator& operator--()
    {
        throw std::runtime_error("Not supported");
    }

    void advance(std::ptrdiff_t n)
    {
        throw std::runtime_error("Not supported");
    }
};

inline StdStringArrayValueIterator StdStringArray::begin() const
{
    return StdStringArrayValueIterator();
}

inline StdStringArrayValueIterator StdStringArray::end() const
{
    return StdStringArrayValueIterator();
}

class StdStringObjectMemberIterator:
    public std::iterator<
        std::bidirectional_iterator_tag,
        StdStringObjectMember>
{
public:
    StdStringObjectMember operator*() const
    {
        throw std::runtime_error("Not supported");
    }

    DerefProxy<StdStringObjectMember> operator->() const
    {
        throw std::runtime_error("Not supported");
    }

    bool operator==(const StdStringObjectMemberIterator &) const
    {
        return true;
    }

    bool operator!=(const StdStringObjectMemberIterator &) const
    {
        return false;
    }

    const StdStringObjectMemberIterator& operator++()
    {
        throw std::runtime_error("Not supported");
    }

    StdStringObjectMemberIterator operator++(int)
    {
        throw std::runtime_error("Not supported");
    }

    const StdStringObjectMemberIterator& operator--()
    {
        throw std::runtime_error("Not supported");
    }
};

inline StdStringObjectMemberIterator StdStringObject::begin() const
{
    return StdStringObjectMemberIterator();
}

inline StdStringObjectMemberIterator StdStringObject::end() const
{
    return StdStringObjectMemberIterator();
}

inline StdStringObjectMemberIterator StdStringObject::find(const std::string &propertyName) const
{
    return StdStringObjectMemberIterator();
}

template<>
struct AdapterTraits<valijson::adapters::StdStringAdapter>
{
    typedef std::string DocumentType;

    static std::string adapterName()
    {
        return "StdStringAdapter";
    }
};

inline bool StdStringFrozenValue::equalTo(const Adapter &other, bool strict) const
{
    return StdStringAdapter(value).equalTo(other, strict);
}

}  // namespace adapters
}  // namespace valijson
<|endoftext|>