<commit_before>/* -------------------------------------------------------------------------- *
 *                       Simbody(tm): SimTKcommon                             *
 * -------------------------------------------------------------------------- *
 * This is part of the SimTK biosimulation toolkit originating from           *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
 *                                                                            *
 * Portions copyright (c) 2009-12 Stanford University and the Authors.        *
 * Authors: Michael Sherman                                                   *
 * Contributors:                                                              *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

#include "SimTKcommon/internal/common.h"
#include "SimTKcommon/internal/String.h"
#include "SimTKcommon/internal/Pathname.h"

#include <string>
using std::string;

#include <cctype>
using std::tolower;

#include <iostream>
#include <fstream>

#ifdef _WIN32
    #define WIN32_LEAN_AND_MEAN
    #define NOMINMAX
    #include <windows.h>
    #include <direct.h>
    #pragma warning(disable:4996) // getenv() is apparently unsafe
#else
    #ifdef __APPLE__
        #include <mach-o/dyld.h>
    #endif
    #include <dlfcn.h>
    #include <dirent.h>
    #include <unistd.h>
#endif

using namespace SimTK;

#ifdef _WIN32
    static const bool IsWindows          = true;
    static const char MyPathSeparator    = '\\';
    static const char OtherPathSeparator = '/';
#else
    static const bool IsWindows          = false;
    static const char MyPathSeparator    = '/';
    static const char OtherPathSeparator = '\\';
#endif

char Pathname::getPathSeparatorChar() {
    return MyPathSeparator;
}

string Pathname::getPathSeparator() {
    return String(getPathSeparatorChar());
}

static void makeNativeSlashesInPlace(string& inout) {
    for (unsigned i=0; i < inout.size(); ++i)
        if (inout[i] == OtherPathSeparator)
            inout[i] = MyPathSeparator;
}

static void addFinalSeparatorInPlace(string& inout) {
    if (!inout.empty() && !Pathname::isPathSeparator(inout[inout.size()-1]))
        inout += MyPathSeparator;
}

static bool beginsWithPathSeparator(const string& in) {
    return !in.empty() && Pathname::isPathSeparator(in[0]);
}

// Remove the last segment of a path name and the separator. The
// returned component does not include a separator.
static void removeLastPathComponentInPlace(string& inout, string& component) {
    component.clear();
    if (inout.empty()) return;

    const string::size_type lastSeparator = inout.find_last_of("/\\");
    if (lastSeparator == string::npos) {
        component = inout;
        inout.clear();
    } else {
        component = inout.substr(lastSeparator+1);
        inout.erase(lastSeparator);
    }
}

static void removeDriveInPlace(string& inout, string& drive) {
    drive.clear();
    if (IsWindows && inout.size() >= 2 && inout[1]==':') {
        drive = (char)tolower(inout[0]);
        inout.erase(0,2);
    }
}

// We assume a path name structure like this:
//   (1) Everything up to and including the final directory separator
//       character is the directory; the rest is the file name. On return
//       we fix the slashes in the directory name to suit the current
//       system ('\' for Windows, '/' otherwise).
//   (2) If the file name contains a ".", characters after the last
//       "." are the extension and the last "." is removed.
//   (5) What's left is the fileName.
// We accept both "/" and "\" as separator characters. We leave the
// case as it was supplied.
// Leading and trailing white space is removed; embedded white space
// remains.
// Leading "X:" for some drive letter X is recognized on Windows as
// a drive specification, otherwise the drive is the current drive.
// That is then removed for further processing.
// Absolute paths are designated like this:
//      Leading "/" means root relative (on the drive).
//      Leading "./" means current working directory relative (on the drive).
//      Leading "../" is interpreted as "./..".
//      Leading "@/" means relative to executable location.
// Above leading characters are removed and replaced with the
// full path name they represent, then the entire path is divided
// into components. If a component is "." or "" (empty) it is
// removed. If a component is ".." it and the previous component
// if any are removed. (".." as a first component will report as
// ill formed.)
// If there is something ill-formed about the file name we'll return
// false.
void Pathname::deconstructPathname( const string&   name,
                                    bool&           isAbsolutePath,
                                    string&         directory,
                                    string&         fileName,
                                    string&         extension)
{
    isAbsolutePath = false;
    directory.erase(); fileName.erase(); extension.erase();

    // Remove all the white space and make all the slashes be forward ones.
    // (For Windows they'll be changed to backslashes later.)
    String processed = String::trimWhiteSpace(name).replaceAllChar('\\', '/');
    if (processed.empty())
        return; // name consisted only of white space

    string drive;
    removeDriveInPlace(processed, drive);

    // Now the drive if any has been removed and we're looking at
    // the beginning of the path name.

    // If the pathname in its entirety is just one of these, append
    // a slash to avoid special cases below.
    if (processed=="." || processed==".." || processed=="@")
        processed += "/";

    // If the path begins with "../" we'll make it ./../ to simplify handling.
    if (processed.substr(0,3) == "../")
        processed.insert(0, "./");

    if (processed.substr(0,1) == "/") {
        isAbsolutePath = true;
        processed.erase(0,1);
        if (drive.empty()) drive = getCurrentDriveLetter();
    } else if (processed.substr(0,2) == "./") {
        isAbsolutePath = true;
        processed.replace(0,2,getCurrentWorkingDirectory(drive));
        removeDriveInPlace(processed, drive);
    } else if (processed.substr(0,2) == "@/") {
        isAbsolutePath = true;
        processed.replace(0,2,getThisExecutableDirectory());
        removeDriveInPlace(processed, drive);
    } else if (!drive.empty()) {
        // Looks like a relative path name. But if it had an initial
        // drive specification, e.g. X:something.txt, that is supposed
        // to be interpreted relative to the current working directory
        // on drive X, just as though it were X:./something.txt.
        isAbsolutePath = true;
        processed.insert(0, getCurrentWorkingDirectory(drive));
        removeDriveInPlace(processed, drive);
    }

    // We may have picked up a new batch of backslashes above.
    processed.replaceAllChar('\\', '/');

    // Now we have the full path name if this is absolute, otherwise
    // we're looking at a relative path name. In any case the last
    // component is the file name if it isn't empty, ".", or "..".

    // Process the ".." segments and eliminate meaningless ones
    // as we go through.
    Array_<string> segmentsInReverse;
    bool isFinalSegment = true; // first time around might be the fileName
    int numDotDotsSeen = 0;
    while (!processed.empty()) {
        string component;
        removeLastPathComponentInPlace(processed, component);
        if (component == "..")
            ++numDotDotsSeen;
        else if (!component.empty() && component != ".") {
            if (numDotDotsSeen)
                --numDotDotsSeen;   // skip component
            else if (isFinalSegment) fileName = component;
            else segmentsInReverse.push_back(component);
        }
        isFinalSegment = false;
    }

    // Now we can put together the canonicalized directory.
    if (isAbsolutePath) {
        if (!drive.empty())
            directory = drive + ":";
        directory += "/";
    }

    for (int i = (int)segmentsInReverse.size()-1; i >= 0; --i)
        directory += segmentsInReverse[i] + "/";

    // Fix the slashes.
    makeNativeSlashesInPlace(directory);

    // If there is a .extension, strip it off.
    string::size_type lastDot = fileName.rfind('.');
    if (lastDot != string::npos) {
        extension = fileName.substr(lastDot);
        fileName.erase(lastDot);
    }
}

bool Pathname::fileExists(const std::string& fileName) {
    std::ifstream f(fileName.c_str());
    return f.good();
    // File is closed by destruction of f.
}

string Pathname::getDefaultInstallDir() {
    string installDir;
    #ifdef _WIN32
        installDir = getEnvironmentVariable("ProgramFiles");
        if (!installDir.empty()) {
            makeNativeSlashesInPlace(installDir);
            addFinalSeparatorInPlace(installDir);
        } else
            installDir = "c:\\Program Files\\";
    #else
        installDir = "/usr/local/";
    #endif
    return installDir;
}

string Pathname::addDirectoryOffset(const string& base, const string& offset) {
    string cleanOffset = beginsWithPathSeparator(offset)
        ? offset.substr(1) : offset; // remove leading path separator
    addFinalSeparatorInPlace(cleanOffset); // add trailing / if non-empty
    string result = base;
    addFinalSeparatorInPlace(result);
    result += cleanOffset;
    return result;
}

string Pathname::getInstallDir(const std::string& envInstallDir,
                                 const std::string& offsetFromDefaultInstallDir)
{   std::string installDir = getEnvironmentVariable(envInstallDir);
    if (!installDir.empty()) {
        makeNativeSlashesInPlace(installDir);
        addFinalSeparatorInPlace(installDir);
    } else
        installDir = addDirectoryOffset(getDefaultInstallDir(), offsetFromDefaultInstallDir);
    return installDir;
}

string Pathname::getThisExecutablePath() {
    char buf[2048];
    #if defined(_WIN32)
        const DWORD nBytes = GetModuleFileName((HMODULE)0, (LPTSTR)buf, sizeof(buf));
        buf[0] = (char)tolower(buf[0]); // drive name
    #elif defined(__APPLE__)
        uint32_t sz = (uint32_t)sizeof(buf);
        int status = _NSGetExecutablePath(buf, &sz);
        assert(status==0); // non-zero means path longer than buf, sz says what's needed
    #else // Linux
        // This isn't automatically null terminated.
        const size_t nBytes = readlink("/proc/self/exe", buf, sizeof(buf));
        buf[nBytes] = '\0';
    #endif
    return string(buf);
}

string Pathname::getThisExecutableDirectory() {
    string path = getThisExecutablePath();
    string component;
    removeLastPathComponentInPlace(path, component);
    path += MyPathSeparator;
    return path;
}

string Pathname::getCurrentDriveLetter() {
    #ifdef _WIN32
        const int which = _getdrive();
        return string() + (char)('a' + which-1);
    #else
        return string();
    #endif
}

string Pathname::getCurrentDrive() {
    #ifdef _WIN32
        return getCurrentDriveLetter() + ":";
    #else
        return string();
    #endif
}

string Pathname::getCurrentWorkingDirectory(const string& drive) {
    char buf[2048];

    #ifdef _WIN32
        const int which = drive.empty() ? 0 : (tolower(drive[0]) - 'a') + 1;
        assert(which >= 0);
        if (which != 0) {
            // Make sure this drive exists.
            const ULONG mask = _getdrives();
            if (!(mask & (1<<(which-1))))
                return getRootDirectory(drive);
        }
        _getdcwd(which, buf, sizeof(buf));
        buf[0] = (char)tolower(buf[0]); // drive letter
    #else
        #ifndef NDEBUG
            char* bufp = getcwd(buf, sizeof(buf));
            assert(bufp != 0); // buf not big enough if this happens
        #else
            (void) getcwd(buf, sizeof(buf));
        #endif
    #endif

    string cwd(buf);
    if (cwd.size() && cwd[cwd.size()-1] != MyPathSeparator)
        cwd += MyPathSeparator;
    return cwd;
}

string Pathname::getRootDirectory(const string& drive) {
    #ifdef _WIN32
        if (drive.empty())
            return getCurrentDrive() + getPathSeparator();
        return String(drive[0]).toLower() + ":" + getPathSeparator();
    #else
        return getPathSeparator();
    #endif
}

bool Pathname::environmentVariableExists(const string& name) {
    return getenv(name.c_str()) != 0;
}

string Pathname::getEnvironmentVariable(const string& name) {
    char* value;
    value = getenv(name.c_str());
    return value ? string(value) : string();
}

<commit_msg>Fix Pathname GCC/Clang warning.<commit_after>/* -------------------------------------------------------------------------- *
 *                       Simbody(tm): SimTKcommon                             *
 * -------------------------------------------------------------------------- *
 * This is part of the SimTK biosimulation toolkit originating from           *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
 *                                                                            *
 * Portions copyright (c) 2009-12 Stanford University and the Authors.        *
 * Authors: Michael Sherman                                                   *
 * Contributors:                                                              *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

#include "SimTKcommon/internal/common.h"
#include "SimTKcommon/internal/String.h"
#include "SimTKcommon/internal/Pathname.h"

#include <string>
using std::string;

#include <cctype>
using std::tolower;

#include <iostream>
#include <fstream>

#ifdef _WIN32
    #define WIN32_LEAN_AND_MEAN
    #define NOMINMAX
    #include <windows.h>
    #include <direct.h>
    #pragma warning(disable:4996) // getenv() is apparently unsafe
#else
    #ifdef __APPLE__
        #include <mach-o/dyld.h>
    #endif
    #include <dlfcn.h>
    #include <dirent.h>
    #include <unistd.h>
#endif

using namespace SimTK;

#ifdef _WIN32
    static const bool IsWindows          = true;
    static const char MyPathSeparator    = '\\';
    static const char OtherPathSeparator = '/';
#else
    static const bool IsWindows          = false;
    static const char MyPathSeparator    = '/';
    static const char OtherPathSeparator = '\\';
#endif

char Pathname::getPathSeparatorChar() {
    return MyPathSeparator;
}

string Pathname::getPathSeparator() {
    return String(getPathSeparatorChar());
}

static void makeNativeSlashesInPlace(string& inout) {
    for (unsigned i=0; i < inout.size(); ++i)
        if (inout[i] == OtherPathSeparator)
            inout[i] = MyPathSeparator;
}

static void addFinalSeparatorInPlace(string& inout) {
    if (!inout.empty() && !Pathname::isPathSeparator(inout[inout.size()-1]))
        inout += MyPathSeparator;
}

static bool beginsWithPathSeparator(const string& in) {
    return !in.empty() && Pathname::isPathSeparator(in[0]);
}

// Remove the last segment of a path name and the separator. The
// returned component does not include a separator.
static void removeLastPathComponentInPlace(string& inout, string& component) {
    component.clear();
    if (inout.empty()) return;

    const string::size_type lastSeparator = inout.find_last_of("/\\");
    if (lastSeparator == string::npos) {
        component = inout;
        inout.clear();
    } else {
        component = inout.substr(lastSeparator+1);
        inout.erase(lastSeparator);
    }
}

static void removeDriveInPlace(string& inout, string& drive) {
    drive.clear();
    if (IsWindows && inout.size() >= 2 && inout[1]==':') {
        drive = (char)tolower(inout[0]);
        inout.erase(0,2);
    }
}

// We assume a path name structure like this:
//   (1) Everything up to and including the final directory separator
//       character is the directory; the rest is the file name. On return
//       we fix the slashes in the directory name to suit the current
//       system ('\' for Windows, '/' otherwise).
//   (2) If the file name contains a ".", characters after the last
//       "." are the extension and the last "." is removed.
//   (5) What's left is the fileName.
// We accept both "/" and "\" as separator characters. We leave the
// case as it was supplied.
// Leading and trailing white space is removed; embedded white space
// remains.
// Leading "X:" for some drive letter X is recognized on Windows as
// a drive specification, otherwise the drive is the current drive.
// That is then removed for further processing.
// Absolute paths are designated like this:
//      Leading "/" means root relative (on the drive).
//      Leading "./" means current working directory relative (on the drive).
//      Leading "../" is interpreted as "./..".
//      Leading "@/" means relative to executable location.
// Above leading characters are removed and replaced with the
// full path name they represent, then the entire path is divided
// into components. If a component is "." or "" (empty) it is
// removed. If a component is ".." it and the previous component
// if any are removed. (".." as a first component will report as
// ill formed.)
// If there is something ill-formed about the file name we'll return
// false.
void Pathname::deconstructPathname( const string&   name,
                                    bool&           isAbsolutePath,
                                    string&         directory,
                                    string&         fileName,
                                    string&         extension)
{
    isAbsolutePath = false;
    directory.erase(); fileName.erase(); extension.erase();

    // Remove all the white space and make all the slashes be forward ones.
    // (For Windows they'll be changed to backslashes later.)
    String processed = String::trimWhiteSpace(name).replaceAllChar('\\', '/');
    if (processed.empty())
        return; // name consisted only of white space

    string drive;
    removeDriveInPlace(processed, drive);

    // Now the drive if any has been removed and we're looking at
    // the beginning of the path name.

    // If the pathname in its entirety is just one of these, append
    // a slash to avoid special cases below.
    if (processed=="." || processed==".." || processed=="@")
        processed += "/";

    // If the path begins with "../" we'll make it ./../ to simplify handling.
    if (processed.substr(0,3) == "../")
        processed.insert(0, "./");

    if (processed.substr(0,1) == "/") {
        isAbsolutePath = true;
        processed.erase(0,1);
        if (drive.empty()) drive = getCurrentDriveLetter();
    } else if (processed.substr(0,2) == "./") {
        isAbsolutePath = true;
        processed.replace(0,2,getCurrentWorkingDirectory(drive));
        removeDriveInPlace(processed, drive);
    } else if (processed.substr(0,2) == "@/") {
        isAbsolutePath = true;
        processed.replace(0,2,getThisExecutableDirectory());
        removeDriveInPlace(processed, drive);
    } else if (!drive.empty()) {
        // Looks like a relative path name. But if it had an initial
        // drive specification, e.g. X:something.txt, that is supposed
        // to be interpreted relative to the current working directory
        // on drive X, just as though it were X:./something.txt.
        isAbsolutePath = true;
        processed.insert(0, getCurrentWorkingDirectory(drive));
        removeDriveInPlace(processed, drive);
    }

    // We may have picked up a new batch of backslashes above.
    processed.replaceAllChar('\\', '/');

    // Now we have the full path name if this is absolute, otherwise
    // we're looking at a relative path name. In any case the last
    // component is the file name if it isn't empty, ".", or "..".

    // Process the ".." segments and eliminate meaningless ones
    // as we go through.
    Array_<string> segmentsInReverse;
    bool isFinalSegment = true; // first time around might be the fileName
    int numDotDotsSeen = 0;
    while (!processed.empty()) {
        string component;
        removeLastPathComponentInPlace(processed, component);
        if (component == "..")
            ++numDotDotsSeen;
        else if (!component.empty() && component != ".") {
            if (numDotDotsSeen)
                --numDotDotsSeen;   // skip component
            else if (isFinalSegment) fileName = component;
            else segmentsInReverse.push_back(component);
        }
        isFinalSegment = false;
    }

    // Now we can put together the canonicalized directory.
    if (isAbsolutePath) {
        if (!drive.empty())
            directory = drive + ":";
        directory += "/";
    }

    for (int i = (int)segmentsInReverse.size()-1; i >= 0; --i)
        directory += segmentsInReverse[i] + "/";

    // Fix the slashes.
    makeNativeSlashesInPlace(directory);

    // If there is a .extension, strip it off.
    string::size_type lastDot = fileName.rfind('.');
    if (lastDot != string::npos) {
        extension = fileName.substr(lastDot);
        fileName.erase(lastDot);
    }
}

bool Pathname::fileExists(const std::string& fileName) {
    std::ifstream f(fileName.c_str());
    return f.good();
    // File is closed by destruction of f.
}

string Pathname::getDefaultInstallDir() {
    string installDir;
    #ifdef _WIN32
        installDir = getEnvironmentVariable("ProgramFiles");
        if (!installDir.empty()) {
            makeNativeSlashesInPlace(installDir);
            addFinalSeparatorInPlace(installDir);
        } else
            installDir = "c:\\Program Files\\";
    #else
        installDir = "/usr/local/";
    #endif
    return installDir;
}

string Pathname::addDirectoryOffset(const string& base, const string& offset) {
    string cleanOffset = beginsWithPathSeparator(offset)
        ? offset.substr(1) : offset; // remove leading path separator
    addFinalSeparatorInPlace(cleanOffset); // add trailing / if non-empty
    string result = base;
    addFinalSeparatorInPlace(result);
    result += cleanOffset;
    return result;
}

string Pathname::getInstallDir(const std::string& envInstallDir,
                                 const std::string& offsetFromDefaultInstallDir)
{   std::string installDir = getEnvironmentVariable(envInstallDir);
    if (!installDir.empty()) {
        makeNativeSlashesInPlace(installDir);
        addFinalSeparatorInPlace(installDir);
    } else
        installDir = addDirectoryOffset(getDefaultInstallDir(), offsetFromDefaultInstallDir);
    return installDir;
}

string Pathname::getThisExecutablePath() {
    char buf[2048];
    #if defined(_WIN32)
        const DWORD nBytes = GetModuleFileName((HMODULE)0, (LPTSTR)buf, sizeof(buf));
        buf[0] = (char)tolower(buf[0]); // drive name
    #elif defined(__APPLE__)
        uint32_t sz = (uint32_t)sizeof(buf);
        int status = _NSGetExecutablePath(buf, &sz);
        assert(status==0); // non-zero means path longer than buf, sz says what's needed
    #else // Linux
        // This isn't automatically null terminated.
        const size_t nBytes = readlink("/proc/self/exe", buf, sizeof(buf));
        buf[nBytes] = '\0';
    #endif
    return string(buf);
}

string Pathname::getThisExecutableDirectory() {
    string path = getThisExecutablePath();
    string component;
    removeLastPathComponentInPlace(path, component);
    path += MyPathSeparator;
    return path;
}

string Pathname::getCurrentDriveLetter() {
    #ifdef _WIN32
        const int which = _getdrive();
        return string() + (char)('a' + which-1);
    #else
        return string();
    #endif
}

string Pathname::getCurrentDrive() {
    #ifdef _WIN32
        return getCurrentDriveLetter() + ":";
    #else
        return string();
    #endif
}

string Pathname::getCurrentWorkingDirectory(const string& drive) {
    char buf[2048];

    #ifdef _WIN32
        const int which = drive.empty() ? 0 : (tolower(drive[0]) - 'a') + 1;
        assert(which >= 0);
        if (which != 0) {
            // Make sure this drive exists.
            const ULONG mask = _getdrives();
            if (!(mask & (1<<(which-1))))
                return getRootDirectory(drive);
        }
        _getdcwd(which, buf, sizeof(buf));
        buf[0] = (char)tolower(buf[0]); // drive letter
    #else
        char* bufp = getcwd(buf, sizeof(buf));
        SimTK_ERRCHK_ALWAYS(bufp != 0,
                "Pathname::getCurrentWorkingDirectory()",
                "Buffer is not big enough to store current working directory.");
    #endif

    string cwd(buf);
    if (cwd.size() && cwd[cwd.size()-1] != MyPathSeparator)
        cwd += MyPathSeparator;
    return cwd;
}

string Pathname::getRootDirectory(const string& drive) {
    #ifdef _WIN32
        if (drive.empty())
            return getCurrentDrive() + getPathSeparator();
        return String(drive[0]).toLower() + ":" + getPathSeparator();
    #else
        return getPathSeparator();
    #endif
}

bool Pathname::environmentVariableExists(const string& name) {
    return getenv(name.c_str()) != 0;
}

string Pathname::getEnvironmentVariable(const string& name) {
    char* value;
    value = getenv(name.c_str());
    return value ? string(value) : string();
}

<|endoftext|>


<commit_before>/**********************************************************************
 *
 *	FILE:			ConvexPlanarOccluder.cpp
 *
 *	DESCRIPTION:	Read/Write osg::ConvexPlanarOccluder in binary format to disk.
 *
 *	CREATED BY:		Auto generated by iveGenerator
 *					and later modified by Rune Schmidt Jensen.
 *
 *	HISTORY:		Created 23.4.2003
 *
 *	Copyright 2003 VR-C
 **********************************************************************/

#include "Exception.h"
#include "Object.h"
#include "ConvexPlanarOccluder.h"
#include "ConvexPlanarPolygon.h"

using namespace ive;

void ConvexPlanarOccluder::write(DataOutputStream* out){
	// Write ConvexPlanarOccluder's identification.
	out->writeInt(IVECONVEXPLANAROCCLUDER);
	// If the osg class is inherited by any other class we should also write this to file.
	osg::Object*  obj = dynamic_cast<osg::Object*>(this);
	if(obj){
		((ive::Object*)(obj))->write(out);
	}
	else
		throw Exception("ConvexPlanarOccluder::write(): Could not cast this osg::ConvexPlanarOccluder to an osg::Object.");
	// Write ConvexPlanarOccluder's properties.

	// Write planar polygon occluder.
	out->writeInt((int)&getOccluder());
	if(&getOccluder())
		((ive::ConvexPlanarPolygon*)(&getOccluder()))->write(out);

	// Write hole list.
	HoleList holeList = getHoleList();
	int size = holeList.size();
	out->writeInt(size);
	for(int i=0; i<size; i++){
		((ive::ConvexPlanarPolygon*)(&holeList[i]))->write(out);
	}
}

void ConvexPlanarOccluder::read(DataInputStream* in){
	// Peek on ConvexPlanarOccluder's identification.
	int id = in->peekInt();
	if(id == IVECONVEXPLANAROCCLUDER){
		// Read ConvexPlanarOccluder's identification.
		id = in->readInt();
		// If the osg class is inherited by any other class we should also read this from file.
		osg::Object*  obj = dynamic_cast<osg::Object*>(this);
		if(obj){
			((ive::Object*)(obj))->read(in);
		}
		else
			throw Exception("ConvexPlanarOccluder::read(): Could not cast this osg::ConvexPlanarOccluder to an osg::Object.");
		// Read ConvexPlanarOccluder's properties

		// Read planar polygon occluder.
		if(in->readInt()){
			osg::ConvexPlanarPolygon* cpp = new osg::ConvexPlanarPolygon();
			((ive::ConvexPlanarPolygon*)(cpp))->read(in);
			setOccluder(*cpp);
		}

		// Read hole list.
		int size = in->readInt();
		for(int i=0; i<size; i++){
			osg::ConvexPlanarPolygon* cpp = new osg::ConvexPlanarPolygon();
			((ive::ConvexPlanarPolygon*)(cpp))->read(in);
			addHole(*cpp);
		}

	}
	else{
		throw Exception("ConvexPlanarOccluder::read(): Expected ConvexPlanarOccluder identification.");
	}
}
<commit_msg>Fix for 64bit build.<commit_after>/**********************************************************************
 *
 *    FILE:            ConvexPlanarOccluder.cpp
 *
 *    DESCRIPTION:    Read/Write osg::ConvexPlanarOccluder in binary format to disk.
 *
 *    CREATED BY:        Auto generated by iveGenerator
 *                    and later modified by Rune Schmidt Jensen.
 *
 *    HISTORY:        Created 23.4.2003
 *
 *    Copyright 2003 VR-C
 **********************************************************************/

#include "Exception.h"
#include "Object.h"
#include "ConvexPlanarOccluder.h"
#include "ConvexPlanarPolygon.h"

using namespace ive;

void ConvexPlanarOccluder::write(DataOutputStream* out){
    // Write ConvexPlanarOccluder's identification.
    out->writeInt(IVECONVEXPLANAROCCLUDER);
    // If the osg class is inherited by any other class we should also write this to file.
    osg::Object*  obj = dynamic_cast<osg::Object*>(this);
    if(obj){
        ((ive::Object*)(obj))->write(out);
    }
    else
        throw Exception("ConvexPlanarOccluder::write(): Could not cast this osg::ConvexPlanarOccluder to an osg::Object.");
    // Write ConvexPlanarOccluder's properties.

    // Write planar polygon occluder.
    ((ive::ConvexPlanarPolygon*)(&getOccluder()))->write(out);

    // Write hole list.
    HoleList holeList = getHoleList();
    int size = holeList.size();
    out->writeInt(size);
    for(int i=0; i<size; i++){
        ((ive::ConvexPlanarPolygon*)(&holeList[i]))->write(out);
    }
}

void ConvexPlanarOccluder::read(DataInputStream* in){
    // Peek on ConvexPlanarOccluder's identification.
    int id = in->peekInt();
    if(id == IVECONVEXPLANAROCCLUDER){
        // Read ConvexPlanarOccluder's identification.
        id = in->readInt();
        // If the osg class is inherited by any other class we should also read this from file.
        osg::Object*  obj = dynamic_cast<osg::Object*>(this);
        if(obj){
            ((ive::Object*)(obj))->read(in);
        }
        else
            throw Exception("ConvexPlanarOccluder::read(): Could not cast this osg::ConvexPlanarOccluder to an osg::Object.");
        // Read ConvexPlanarOccluder's properties

        // Read planar polygon occluder.
        osg::ConvexPlanarPolygon* cpp = &getOccluder();
        ((ive::ConvexPlanarPolygon*)(cpp))->read(in);

        // Read hole list.
        int size = in->readInt();
        for(int i=0; i<size; i++){
            osg::ConvexPlanarPolygon* cpp = new osg::ConvexPlanarPolygon();
            ((ive::ConvexPlanarPolygon*)(cpp))->read(in);
            addHole(*cpp);
        }

    }
    else{
        throw Exception("ConvexPlanarOccluder::read(): Expected ConvexPlanarOccluder identification.");
    }
}
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// MOOSE includes
#include "InputParameters.h"
#include "MultiMooseEnum.h"
#include "gtest/gtest.h"

TEST(InputParameters, checkControlParamPrivateError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addPrivateParam<Real>("private", 1);
    params.declareControllable("private");
    params.checkParams("");
    FAIL() << "checkParams failed to catch private control param";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("private parameter '' marked controllable") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

// This tests for the bug https://github.com/idaholab/moose/issues/8586.
// It makes sure that range-checked input file parameters comparison functions
// do absolute floating point comparisons instead of using a default epsilon.
TEST(InputParameters, checkRangeCheckedParam)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addRangeCheckedParam<Real>("p", 1.000000000000001, "p = 1", "Some doc");
    params.checkParams("");
    FAIL() << "range checked input param failed to catch 1.000000000000001 != 1";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("Range check failed for param") != std::string::npos)
        << "range check failed with unexpected error: " << msg;
  }
}

TEST(InputParameters, checkControlParamTypeError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addParam<PostprocessorName>("pp_name", "make_it_valid", "Some doc");
    params.declareControllable("pp_name");
    params.checkParams("");
    FAIL() << "checkParams failed to catch invalid control param type";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("non-controllable type") != std::string::npos)
        << "failed with unexpected error:" << msg;
  }
}

TEST(InputParameters, checkControlParamValidError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.declareControllable("not_valid");
    params.checkParams("");
    FAIL() << "checkParams failed to catch non existing control param";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("cannot be marked as controllable") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

TEST(InputParameters, checkSuppressedError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.suppressParameter<int>("nonexistent");
    FAIL() << "failed to error on supression of nonexisting parameter";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("Unable to suppress nonexistent parameter") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

TEST(InputParameters, checkSetDocString)
{
  InputParameters params = emptyInputParameters();
  params.addParam<Real>("little_guy", "What about that little guy?");
  params.setDocString("little_guy", "That little guy, I wouldn't worry about that little_guy.");
  ASSERT_TRUE(params.getDocString("little_guy")
                  .find("That little guy, I wouldn't worry about that little_guy.") !=
              std::string::npos)
      << "retrieved doc string has unexpected value '" << params.getDocString("little_guy") << "'";
}

TEST(InputParameters, checkSetDocStringError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.setDocString("little_guy", "That little guy, I wouldn't worry about that little_guy.");
    FAIL() << "failed to error on attempt to set non-existing parameter";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("Unable to set the documentation string (using setDocString)") !=
                std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

void
testBadParamName(const std::string & name)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addParam<bool>(name, "Doc");
    FAIL() << "failed to error on attempt to set invalid parameter name";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    EXPECT_TRUE(msg.find("Invalid parameter name") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

/// Just make sure we don't allow invalid parameter names
TEST(InputParameters, checkParamName)
{
  testBadParamName("p 0");
  testBadParamName("p-0");
  testBadParamName("p!0");
}

TEST(InputParameters, applyParameter)
{
  InputParameters p1 = emptyInputParameters();
  p1.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=0 bar=1", "foo"), "testing");
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));

  InputParameters p2 = emptyInputParameters();
  p2.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=42 bar=43", "foo"), "testing");
  EXPECT_TRUE(p2.get<MultiMooseEnum>("enum").contains("foo"));

  p2.set<MultiMooseEnum>("enum") = "bar";
  p1.applyParameter(p2, "enum");
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("bar"));
}

TEST(InputParameters, applyParameters)
{
  // First enum
  InputParameters p1 = emptyInputParameters();
  p1.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=0 bar=1", "foo"), "testing");
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));

  // Second enum
  InputParameters p2 = emptyInputParameters();
  p2.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=42 bar=43", "foo"), "testing");
  EXPECT_TRUE(p2.get<MultiMooseEnum>("enum").contains("foo"));
  EXPECT_FALSE(p2.get<MultiMooseEnum>("enum").contains("bar"));

  // Change second and apply to first
  p2.set<MultiMooseEnum>("enum") = "bar";
  p1.applyParameters(p2);
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("foo"));

  // Change back first (in "quiet_mode") then reapply second, first should change again
  p1.set<MultiMooseEnum>("enum", true) = "foo";
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
  p1.applyParameters(p2);
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("foo"));

  // Change back first then reapply second, first should not change
  p1.set<MultiMooseEnum>("enum") = "foo";
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
  p1.applyParameters(p2);
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
}

TEST(InputParameters, applyParametersPrivateOverride)
{
  InputParameters p1 = emptyInputParameters();
  p1.addPrivateParam<bool>("_flag", true);
  EXPECT_TRUE(p1.get<bool>("_flag"));

  InputParameters p2 = emptyInputParameters();
  p2.addPrivateParam<bool>("_flag", false);
  EXPECT_FALSE(p2.get<bool>("_flag"));

  p1.applySpecificParameters(p2, {"_flag"}, true);
  EXPECT_FALSE(p1.get<bool>("_flag"));
}

TEST(InputParameters, makeParamRequired)
{
  InputParameters params = emptyInputParameters();
  params.addParam<Real>("good_param", "documentation");
  params.addParam<Real>("wrong_param_type", "documentation");

  // Require existing parameter with the appropriate type
  EXPECT_FALSE(params.isParamRequired("good_param"));
  params.makeParamRequired<Real>("good_param");
  EXPECT_TRUE(params.isParamRequired("good_param"));

  // Require existing parameter with the wrong type
  try
  {
    params.makeParamRequired<PostprocessorName>("wrong_param_type");
    FAIL() << "failed to error on attempt to change a parameter type when making it required";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    EXPECT_TRUE(msg.find("Unable to require nonexistent parameter: wrong_param_type") !=
                std::string::npos)
        << "failed with unexpected error: " << msg;
  }

  // Require non-existing parameter
  try
  {
    params.makeParamRequired<PostprocessorName>("wrong_param_name");
    FAIL() << "failed to error on attempt to require a non-existent parameter";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    EXPECT_TRUE(msg.find("Unable to require nonexistent parameter: wrong_param_name") !=
                std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}
<commit_msg>Unit tests for defaulted PPs (#14525)<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

// MOOSE includes
#include "InputParameters.h"
#include "MultiMooseEnum.h"
#include "gtest/gtest.h"

TEST(InputParameters, checkControlParamPrivateError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addPrivateParam<Real>("private", 1);
    params.declareControllable("private");
    params.checkParams("");
    FAIL() << "checkParams failed to catch private control param";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("private parameter '' marked controllable") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

// This tests for the bug https://github.com/idaholab/moose/issues/8586.
// It makes sure that range-checked input file parameters comparison functions
// do absolute floating point comparisons instead of using a default epsilon.
TEST(InputParameters, checkRangeCheckedParam)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addRangeCheckedParam<Real>("p", 1.000000000000001, "p = 1", "Some doc");
    params.checkParams("");
    FAIL() << "range checked input param failed to catch 1.000000000000001 != 1";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("Range check failed for param") != std::string::npos)
        << "range check failed with unexpected error: " << msg;
  }
}

TEST(InputParameters, checkControlParamTypeError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addParam<PostprocessorName>("pp_name", "make_it_valid", "Some doc");
    params.declareControllable("pp_name");
    params.checkParams("");
    FAIL() << "checkParams failed to catch invalid control param type";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("non-controllable type") != std::string::npos)
        << "failed with unexpected error:" << msg;
  }
}

TEST(InputParameters, checkControlParamValidError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.declareControllable("not_valid");
    params.checkParams("");
    FAIL() << "checkParams failed to catch non existing control param";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("cannot be marked as controllable") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

TEST(InputParameters, checkSuppressedError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.suppressParameter<int>("nonexistent");
    FAIL() << "failed to error on supression of nonexisting parameter";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("Unable to suppress nonexistent parameter") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

TEST(InputParameters, checkSetDocString)
{
  InputParameters params = emptyInputParameters();
  params.addParam<Real>("little_guy", "What about that little guy?");
  params.setDocString("little_guy", "That little guy, I wouldn't worry about that little_guy.");
  ASSERT_TRUE(params.getDocString("little_guy")
                  .find("That little guy, I wouldn't worry about that little_guy.") !=
              std::string::npos)
      << "retrieved doc string has unexpected value '" << params.getDocString("little_guy") << "'";
}

TEST(InputParameters, checkSetDocStringError)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.setDocString("little_guy", "That little guy, I wouldn't worry about that little_guy.");
    FAIL() << "failed to error on attempt to set non-existing parameter";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("Unable to set the documentation string (using setDocString)") !=
                std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

void
testBadParamName(const std::string & name)
{
  try
  {
    InputParameters params = emptyInputParameters();
    params.addParam<bool>(name, "Doc");
    FAIL() << "failed to error on attempt to set invalid parameter name";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    EXPECT_TRUE(msg.find("Invalid parameter name") != std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

/// Just make sure we don't allow invalid parameter names
TEST(InputParameters, checkParamName)
{
  testBadParamName("p 0");
  testBadParamName("p-0");
  testBadParamName("p!0");
}

TEST(InputParameters, applyParameter)
{
  InputParameters p1 = emptyInputParameters();
  p1.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=0 bar=1", "foo"), "testing");
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));

  InputParameters p2 = emptyInputParameters();
  p2.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=42 bar=43", "foo"), "testing");
  EXPECT_TRUE(p2.get<MultiMooseEnum>("enum").contains("foo"));

  p2.set<MultiMooseEnum>("enum") = "bar";
  p1.applyParameter(p2, "enum");
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("bar"));
}

TEST(InputParameters, applyParameters)
{
  // First enum
  InputParameters p1 = emptyInputParameters();
  p1.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=0 bar=1", "foo"), "testing");
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));

  // Second enum
  InputParameters p2 = emptyInputParameters();
  p2.addParam<MultiMooseEnum>("enum", MultiMooseEnum("foo=42 bar=43", "foo"), "testing");
  EXPECT_TRUE(p2.get<MultiMooseEnum>("enum").contains("foo"));
  EXPECT_FALSE(p2.get<MultiMooseEnum>("enum").contains("bar"));

  // Change second and apply to first
  p2.set<MultiMooseEnum>("enum") = "bar";
  p1.applyParameters(p2);
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("foo"));

  // Change back first (in "quiet_mode") then reapply second, first should change again
  p1.set<MultiMooseEnum>("enum", true) = "foo";
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
  p1.applyParameters(p2);
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("foo"));

  // Change back first then reapply second, first should not change
  p1.set<MultiMooseEnum>("enum") = "foo";
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
  p1.applyParameters(p2);
  EXPECT_FALSE(p1.get<MultiMooseEnum>("enum").contains("bar"));
  EXPECT_TRUE(p1.get<MultiMooseEnum>("enum").contains("foo"));
}

TEST(InputParameters, applyParametersPrivateOverride)
{
  InputParameters p1 = emptyInputParameters();
  p1.addPrivateParam<bool>("_flag", true);
  EXPECT_TRUE(p1.get<bool>("_flag"));

  InputParameters p2 = emptyInputParameters();
  p2.addPrivateParam<bool>("_flag", false);
  EXPECT_FALSE(p2.get<bool>("_flag"));

  p1.applySpecificParameters(p2, {"_flag"}, true);
  EXPECT_FALSE(p1.get<bool>("_flag"));
}

TEST(InputParameters, makeParamRequired)
{
  InputParameters params = emptyInputParameters();
  params.addParam<Real>("good_param", "documentation");
  params.addParam<Real>("wrong_param_type", "documentation");

  // Require existing parameter with the appropriate type
  EXPECT_FALSE(params.isParamRequired("good_param"));
  params.makeParamRequired<Real>("good_param");
  EXPECT_TRUE(params.isParamRequired("good_param"));

  // Require existing parameter with the wrong type
  try
  {
    params.makeParamRequired<PostprocessorName>("wrong_param_type");
    FAIL() << "failed to error on attempt to change a parameter type when making it required";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    EXPECT_TRUE(msg.find("Unable to require nonexistent parameter: wrong_param_type") !=
                std::string::npos)
        << "failed with unexpected error: " << msg;
  }

  // Require non-existing parameter
  try
  {
    params.makeParamRequired<PostprocessorName>("wrong_param_name");
    FAIL() << "failed to error on attempt to require a non-existent parameter";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    EXPECT_TRUE(msg.find("Unable to require nonexistent parameter: wrong_param_name") !=
                std::string::npos)
        << "failed with unexpected error: " << msg;
  }
}

TEST(InputParameters, setPPandVofPP)
{
  // programmatically set default value of PPName parameter
  InputParameters p1 = emptyInputParameters();
  p1.addParam<std::vector<PostprocessorName>>("pp_name", "testing");
  p1.set<std::vector<PostprocessorName>>("pp_name") = {"first", "second", "third"};

  // check if we have a vector of pps
  EXPECT_TRUE(!p1.isSinglePostprocessor("pp_name")) << "Failed to detect vector of PPs";

  // check what happens if default value is requested
  /*
  try
  {
    p1.hasDefaultPostprocessorValue("pp_name", 2);
    FAIL() << "failed to error on supression of nonexisting parameter";
  }
  catch (const std::exception & e)
  {
    std::string msg(e.what());
    ASSERT_TRUE(msg.find("Attempting to access _have_default_postprocessor_val") !=
  std::string::npos)
        << "failed with unexpected error: " << msg;
  }
  */

  // EXPECT_EQ(p1.getDefaultPostprocessorValue("pp_name"), 1);
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2017, Randolph Voorhies, Shane Grant
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
      * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      * Neither the name of cereal nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_TEST_DEFER_H_
#define CEREAL_TEST_DEFER_H_
#include "common.hpp"

struct DeferNode;

struct DeferRelation
{
  std::shared_ptr<DeferNode> node;
  int x;
  std::string y;

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar( node, x, y );
  }

  bool operator==( DeferRelation const & other ) const;
};

struct DeferNode
{
  DeferNode() = default;
  DeferNode( size_t id_, std::mt19937 & gen ) :
      id(id_),
      w(random_value<long>(gen)),
      iser{random_value<int>(gen), random_value<int>(gen)},
      ispl{random_value<int>(gen), random_value<int>(gen)},
      eser{random_value<int>(gen), random_value<int>(gen)},
      espl{random_value<int>(gen), random_value<int>(gen)},
      relations(),
      z(random_value<char>(gen))
  { }

  size_t id;
  long w;

  StructInternalSerialize iser;
  StructInternalSplit     ispl;
  StructExternalSerialize eser;
  StructExternalSplit     espl;

  std::vector<DeferRelation> relations;

  char z;

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar( id, w,
        cereal::defer( iser ),
        cereal::defer( ispl ),
        cereal::defer( eser ),
        cereal::defer( espl ),
        cereal::defer( relations ),
        z );
  }

  bool operator==( DeferNode const & other ) const
  {
    bool relationsEqual = true;

    if( relations.size() == other.relations.size() )
      for( size_t i = 0; i < relations.size(); ++i )
        relationsEqual &= relations[i] == other.relations[i];
    else
      relationsEqual = false;

    return id == other.id && w == other.w &&
           iser == other.iser && ispl == other.ispl &&
           eser == other.eser && espl == other.espl &&
           relationsEqual;
  }
};

inline std::ostream& operator<<(std::ostream& os, DeferRelation const & s)
{
  os << "[node(id): " << (s.node ? std::to_string(s.node->id) : "null") << " x: " << s.x << " y: " << s.y << "]";
  return os;
}

bool DeferRelation::operator==( DeferRelation const & other ) const
{
  return x == other.x && y == other.y && node->id == other.node->id;
}

inline std::ostream& operator<<(std::ostream& os, DeferNode const & s)
{
  os << "[id: " << s.id << " w " << s.w << " iser " << s.iser;
  os << " ispl " << s.ispl << " eser " << s.eser << " espl " << s.espl;
  os << " relations (size: " << s.relations.size() << "): ";
  for( auto & r : s.relations )
    os << r;
  os << " z " << s.z << "]";
  return os;
}

template <class IArchive, class OArchive> inline
void test_defer()
{
  std::random_device rd;
  std::mt19937 gen(rd());

  for(int ii=0; ii<100; ++ii)
  {
    size_t id = 0;
    std::vector<std::shared_ptr<DeferNode>> o_nodes0(1);
    for( auto & node : o_nodes0 )
      node = std::make_shared<DeferNode>(id++, gen);

    std::vector<std::shared_ptr<DeferNode>> o_nodes1(1);
    for( auto & node : o_nodes1 )
      node = std::make_shared<DeferNode>(id++, gen);

    std::shuffle( o_nodes1.begin(), o_nodes1.end(), gen );

    for( auto & node : o_nodes0 )
    {
      node->relations.resize( random_index( 0, 100, gen ) );
      for( auto & r : node->relations )
        r = {o_nodes0[random_index(0, o_nodes0.size() - 1, gen)],
             random_value<int>(gen), random_basic_string<char>(gen)};
    }

    for( auto & node : o_nodes1 )
    {
      node->relations.resize( random_index( 0, 100, gen ) );
      for( auto & r : node->relations )
        r = {o_nodes0[random_index(0, o_nodes0.size() - 1, gen)],
             random_value<int>(gen), random_basic_string<char>(gen)};
    }

    std::ostringstream os;
    {
      OArchive oar(os);

      oar( o_nodes0 );
      oar( o_nodes1 );
      oar.serializeDeferments();
      // TODO: throw exception if deferments not done when destructor fires
    }

    decltype(o_nodes0) i_nodes0;
    decltype(o_nodes1) i_nodes1;

    std::istringstream is(os.str());
    {
      IArchive iar(is);

      iar( i_nodes0 );
      iar( i_nodes1 );
      iar.serializeDeferments();
    }

    check_ptr_collection(o_nodes0, i_nodes0);
    check_ptr_collection(o_nodes1, i_nodes1);
  }
}

#endif // CEREAL_TEST_DEFER_H_
<commit_msg>make msvc12 happy<commit_after>/*
  Copyright (c) 2017, Randolph Voorhies, Shane Grant
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
      * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      * Neither the name of cereal nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_TEST_DEFER_H_
#define CEREAL_TEST_DEFER_H_
#include "common.hpp"

struct DeferNode;

struct DeferRelation
{
  std::shared_ptr<DeferNode> node;
  int x;
  std::string y;

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar( node, x, y );
  }

  bool operator==( DeferRelation const & other ) const;
};

struct DeferNode
{
  DeferNode() = default;
  DeferNode( size_t id_, std::mt19937 & gen ) :
      id(id_),
      w(random_value<long>(gen)),
      iser{random_value<int>(gen), random_value<int>(gen)},
      ispl{random_value<int>(gen), random_value<int>(gen)},
      eser{random_value<int>(gen), random_value<int>(gen)},
      espl{random_value<int>(gen), random_value<int>(gen)},
      relations(),
      z(random_value<char>(gen))
  { }

  size_t id;
  long w;

  StructInternalSerialize iser;
  StructInternalSplit     ispl;
  StructExternalSerialize eser;
  StructExternalSplit     espl;

  std::vector<DeferRelation> relations;

  char z;

  template <class Archive>
  void serialize( Archive & ar )
  {
    ar( id, w,
        cereal::defer( iser ),
        cereal::defer( ispl ),
        cereal::defer( eser ),
        cereal::defer( espl ),
        cereal::defer( relations ),
        z );
  }

  bool operator==( DeferNode const & other ) const
  {
    bool relationsEqual = true;

    if( relations.size() == other.relations.size() )
      for( size_t i = 0; i < relations.size(); ++i )
        relationsEqual &= relations[i] == other.relations[i];
    else
      relationsEqual = false;

    return id == other.id && w == other.w &&
           iser == other.iser && ispl == other.ispl &&
           eser == other.eser && espl == other.espl &&
           relationsEqual;
  }
};

inline std::ostream& operator<<(std::ostream& os, DeferRelation const & s)
{
  os << "[node(id): " << (s.node ? std::to_string(s.node->id) : "null") << " x: " << s.x << " y: " << s.y << "]";
  return os;
}

bool DeferRelation::operator==( DeferRelation const & other ) const
{
  return x == other.x && y == other.y && node->id == other.node->id;
}

inline std::ostream& operator<<(std::ostream& os, DeferNode const & s)
{
  os << "[id: " << s.id << " w " << s.w << " iser " << s.iser;
  os << " ispl " << s.ispl << " eser " << s.eser << " espl " << s.espl;
  os << " relations (size: " << s.relations.size() << "): ";
  for( auto & r : s.relations )
    os << r;
  os << " z " << s.z << "]";
  return os;
}

template <class IArchive, class OArchive> inline
void test_defer()
{
  std::random_device rd;
  std::mt19937 gen(rd());

  for(int ii=0; ii<100; ++ii)
  {
    size_t id = 0;
    std::vector<std::shared_ptr<DeferNode>> o_nodes0(1);
    for( auto & node : o_nodes0 )
      node = std::make_shared<DeferNode>(id++, gen);

    std::vector<std::shared_ptr<DeferNode>> o_nodes1(1);
    for( auto & node : o_nodes1 )
      node = std::make_shared<DeferNode>(id++, gen);

    std::shuffle( o_nodes1.begin(), o_nodes1.end(), gen );

    for( auto & node : o_nodes0 )
    {
      node->relations.resize( random_index( 0, 100, gen ) );
      for (auto & r : node->relations)
      {
        r = { o_nodes0[random_index( 0, o_nodes0.size() - 1, gen )],
             random_value<int>( gen ), random_basic_string<char>( gen ) };
      }
    }

    for( auto & node : o_nodes1 )
    {
      node->relations.resize( random_index( 0, 100, gen ) );
      for (auto & r : node->relations)
      {
        r = { o_nodes0[random_index( 0, o_nodes0.size() - 1, gen )],
             random_value<int>( gen ), random_basic_string<char>( gen ) };
      }
    }

    std::ostringstream os;
    {
      OArchive oar(os);

      oar( o_nodes0 );
      oar( o_nodes1 );
      oar.serializeDeferments();
      // TODO: throw exception if deferments not done when destructor fires
    }

    decltype(o_nodes0) i_nodes0;
    decltype(o_nodes1) i_nodes1;

    std::istringstream is(os.str());
    {
      IArchive iar(is);

      iar( i_nodes0 );
      iar( i_nodes1 );
      iar.serializeDeferments();
    }

    check_ptr_collection(o_nodes0, i_nodes0);
    check_ptr_collection(o_nodes1, i_nodes1);
  }
}

#endif // CEREAL_TEST_DEFER_H_
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <sdr/contact/viewcontactofsdrpathobj.hxx>
#include <svx/svdopath.hxx>
#include <svx/sdr/primitive2d/sdrattributecreator.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <sdr/primitive2d/sdrpathprimitive2d.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>

namespace sdr
{
    namespace contact
    {
        ViewContactOfSdrPathObj::ViewContactOfSdrPathObj(SdrPathObj& rPathObj)
        :   ViewContactOfTextObj(rPathObj)
        {
        }

        ViewContactOfSdrPathObj::~ViewContactOfSdrPathObj()
        {
        }

        drawinglayer::primitive2d::Primitive2DSequence ViewContactOfSdrPathObj::createViewIndependentPrimitive2DSequence() const
        {
            const SfxItemSet& rItemSet = GetPathObj().GetMergedItemSet();
            const drawinglayer::attribute::SdrLineFillShadowTextAttribute aAttribute(
                drawinglayer::primitive2d::createNewSdrLineFillShadowTextAttribute(
                    rItemSet,
                    GetPathObj().getText(0),
                    false));
            basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
            Point aGridOff = GetPathObj().GetGridOffset();
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            aUnitPolyPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix( aGridOff.X(), aGridOff.Y() ) );
            sal_uInt32 nPolyCount(aUnitPolyPolygon.count());
            sal_uInt32 nPointCount(0);

            for(sal_uInt32 a(0); a < nPolyCount; a++)
            {
                nPointCount += aUnitPolyPolygon.getB2DPolygon(a).count();
            }

            if(!nPointCount)
            {
                OSL_FAIL("PolyPolygon object without geometry detected, this should not be created (!)");
                basegfx::B2DPolygon aFallbackLine;
                aFallbackLine.append(basegfx::B2DPoint(0.0, 0.0));
                aFallbackLine.append(basegfx::B2DPoint(1000.0, 1000.0));
                aUnitPolyPolygon = basegfx::B2DPolyPolygon(aFallbackLine);

                nPolyCount = 1;
            }

            // prepare object transformation and unit polygon (direct model data)
            basegfx::B2DHomMatrix aObjectMatrix;
            const bool bIsLine(
                !aUnitPolyPolygon.areControlPointsUsed()
                && 1 == nPolyCount
                && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());

            if(bIsLine)
            {
                // special handling for single line mode (2 points)
                const basegfx::B2DPolygon aSubPolygon(aUnitPolyPolygon.getB2DPolygon(0));
                const basegfx::B2DPoint aStart(aSubPolygon.getB2DPoint(0));
                const basegfx::B2DPoint aEnd(aSubPolygon.getB2DPoint(1));
                const basegfx::B2DVector aLine(aEnd - aStart);

                // #i102548# create new unit polygon for line (horizontal)
                basegfx::B2DPolygon aNewPolygon;
                aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
                aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
                aUnitPolyPolygon.setB2DPolygon(0, aNewPolygon);

                // #i102548# fill objectMatrix with rotation and offset (no shear for lines)
                aObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
                    aLine.getLength(), 1.0,
                    0.0,
                    atan2(aLine.getY(), aLine.getX()),
                    aStart.getX(), aStart.getY());
            }
            else
            {
                // #i102548# create unscaled, unsheared, unrotated and untranslated polygon
                // (unit polygon) by creating the object matrix and back-transforming the polygon
                const basegfx::B2DRange aObjectRange(basegfx::tools::getRange(aUnitPolyPolygon));
                const GeoStat& rGeoStat(GetPathObj().GetGeoStat());
                const double fWidth(aObjectRange.getWidth());
                const double fHeight(aObjectRange.getHeight());
                const double fScaleX(basegfx::fTools::equalZero(fWidth) ? 1.0 : fWidth);
                const double fScaleY(basegfx::fTools::equalZero(fHeight) ? 1.0 : fHeight);

                aObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
                    fScaleX, fScaleY,
                    rGeoStat.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0,
                    rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * F_PI18000 : 0.0,
                    aObjectRange.getMinX(), aObjectRange.getMinY());

                // create unit polygon from object's absolute path
                basegfx::B2DHomMatrix aInverse(aObjectMatrix);
                aInverse.invert();
                aUnitPolyPolygon.transform(aInverse);
            }

            // create primitive. Always create primitives to allow the decomposition of
            // SdrPathPrimitive2D to create needed invisible elements for HitTest and/or BoundRect
            const drawinglayer::primitive2d::Primitive2DReference xReference(
                new drawinglayer::primitive2d::SdrPathPrimitive2D(
                    aObjectMatrix,
                    aAttribute,
                    aUnitPolyPolygon));

            return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
        }
    } // end of namespace contact
} // end of namespace sdr

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>refactor ensuring polygon has at least a line in it<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <sdr/contact/viewcontactofsdrpathobj.hxx>
#include <svx/svdopath.hxx>
#include <svx/sdr/primitive2d/sdrattributecreator.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <sdr/primitive2d/sdrpathprimitive2d.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>

namespace sdr
{
    namespace contact
    {
        ViewContactOfSdrPathObj::ViewContactOfSdrPathObj(SdrPathObj& rPathObj)
        :   ViewContactOfTextObj(rPathObj)
        {
        }

        ViewContactOfSdrPathObj::~ViewContactOfSdrPathObj()
        {
        }

        static sal_uInt32 ensureGeometry(basegfx::B2DPolyPolygon& rUnitPolyPolygon)
        {
            sal_uInt32 nPolyCount(rUnitPolyPolygon.count());
            sal_uInt32 nPointCount(0);

            for(sal_uInt32 a(0); a < nPolyCount; a++)
            {
                nPointCount += rUnitPolyPolygon.getB2DPolygon(a).count();
            }

            if(!nPointCount)
            {
                OSL_FAIL("PolyPolygon object without geometry detected, this should not be created (!)");
                basegfx::B2DPolygon aFallbackLine;
                aFallbackLine.append(basegfx::B2DPoint(0.0, 0.0));
                aFallbackLine.append(basegfx::B2DPoint(1000.0, 1000.0));
                rUnitPolyPolygon = basegfx::B2DPolyPolygon(aFallbackLine);

                nPolyCount = 1;
            }

            return nPolyCount;
        }

        drawinglayer::primitive2d::Primitive2DSequence ViewContactOfSdrPathObj::createViewIndependentPrimitive2DSequence() const
        {
            const SfxItemSet& rItemSet = GetPathObj().GetMergedItemSet();
            const drawinglayer::attribute::SdrLineFillShadowTextAttribute aAttribute(
                drawinglayer::primitive2d::createNewSdrLineFillShadowTextAttribute(
                    rItemSet,
                    GetPathObj().getText(0),
                    false));
            basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
            Point aGridOff = GetPathObj().GetGridOffset();
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            aUnitPolyPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix( aGridOff.X(), aGridOff.Y() ) );
            sal_uInt32 nPolyCount(ensureGeometry(aUnitPolyPolygon));

            // prepare object transformation and unit polygon (direct model data)
            basegfx::B2DHomMatrix aObjectMatrix;
            const bool bIsLine(
                !aUnitPolyPolygon.areControlPointsUsed()
                && 1 == nPolyCount
                && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());

            if(bIsLine)
            {
                // special handling for single line mode (2 points)
                const basegfx::B2DPolygon aSubPolygon(aUnitPolyPolygon.getB2DPolygon(0));
                const basegfx::B2DPoint aStart(aSubPolygon.getB2DPoint(0));
                const basegfx::B2DPoint aEnd(aSubPolygon.getB2DPoint(1));
                const basegfx::B2DVector aLine(aEnd - aStart);

                // #i102548# create new unit polygon for line (horizontal)
                basegfx::B2DPolygon aNewPolygon;
                aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
                aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
                aUnitPolyPolygon.setB2DPolygon(0, aNewPolygon);

                // #i102548# fill objectMatrix with rotation and offset (no shear for lines)
                aObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
                    aLine.getLength(), 1.0,
                    0.0,
                    atan2(aLine.getY(), aLine.getX()),
                    aStart.getX(), aStart.getY());
            }
            else
            {
                // #i102548# create unscaled, unsheared, unrotated and untranslated polygon
                // (unit polygon) by creating the object matrix and back-transforming the polygon
                const basegfx::B2DRange aObjectRange(basegfx::tools::getRange(aUnitPolyPolygon));
                const GeoStat& rGeoStat(GetPathObj().GetGeoStat());
                const double fWidth(aObjectRange.getWidth());
                const double fHeight(aObjectRange.getHeight());
                const double fScaleX(basegfx::fTools::equalZero(fWidth) ? 1.0 : fWidth);
                const double fScaleY(basegfx::fTools::equalZero(fHeight) ? 1.0 : fHeight);

                aObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
                    fScaleX, fScaleY,
                    rGeoStat.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0,
                    rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * F_PI18000 : 0.0,
                    aObjectRange.getMinX(), aObjectRange.getMinY());

                // create unit polygon from object's absolute path
                basegfx::B2DHomMatrix aInverse(aObjectMatrix);
                aInverse.invert();
                aUnitPolyPolygon.transform(aInverse);
            }

            // create primitive. Always create primitives to allow the decomposition of
            // SdrPathPrimitive2D to create needed invisible elements for HitTest and/or BoundRect
            const drawinglayer::primitive2d::Primitive2DReference xReference(
                new drawinglayer::primitive2d::SdrPathPrimitive2D(
                    aObjectMatrix,
                    aAttribute,
                    aUnitPolyPolygon));

            return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
        }
    } // end of namespace contact
} // end of namespace sdr

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "mock/serializer_filestream.hpp"

#include "buffer_cache/buffer_cache.hpp"
#include "perfmon/core.hpp"

namespace mock {

// Maybe we should have just used a blob for this.

serializer_file_read_stream_t::serializer_file_read_stream_t(serializer_t *serializer)
    : known_size_(-1), position_(0) {
    mirrored_cache_config_t config;
    cache_.init(new cache_t(serializer, config, &get_global_perfmon_collection()));
    if (cache_->contains_block(0)) {
        // SAMRSI: Call a different txn constructor, instead of passing a NULL disk_ack_signal?
        transaction_t txn(cache_.get(), rwi_read, 0, repli_timestamp_t::invalid, order_token_t::ignore, NULL);
        buf_lock_t bufzero(&txn, 0, rwi_read);
        const void *data = bufzero.get_data_read();
        known_size_ = *static_cast<const int64_t *>(data);
        guarantee(known_size_ >= 0);
    }
}

serializer_file_read_stream_t::~serializer_file_read_stream_t() { }

MUST_USE int64_t serializer_file_read_stream_t::read(void *p, int64_t n) {
    if (known_size_ == -1) {
        return -1;
    }

    guarantee(n >= 0);
    const int64_t real_size = known_size_ + sizeof(int64_t);
    const int64_t real_position = position_ + sizeof(int64_t);

    if (real_position == real_size || n == 0) {
        return 0;
    }

    const block_size_t block_size = cache_->get_block_size();
    const int64_t block_number = real_position / block_size.value();
    const int64_t block_offset = real_position % block_size.value();

    const int64_t s = std::min(real_position + n, real_size);
    const int64_t end_block_offset = (s < block_size.value() * (block_number + 1)) ? s % block_size.value() : block_size.value();
    const int64_t num_copied = end_block_offset - block_offset;
    rassert(num_copied > 0);

    if (block_number >= MAX_BLOCK_ID) {
        return -1;
    }

    // SAMRSI: Call a different txn constructor, instead of passing a NULL disk_ack_signal?
    transaction_t txn(cache_.get(), rwi_read, 0, repli_timestamp_t::invalid, order_token_t::ignore, NULL);
    buf_lock_t block(&txn, block_number, rwi_read);
    const char *data = static_cast<const char *>(block.get_data_read());
    memcpy(p, data + block_offset, num_copied);
    return num_copied;
}

serializer_file_write_stream_t::serializer_file_write_stream_t(serializer_t *serializer) : size_(0) {
    cache_t::create(serializer);
    mirrored_cache_config_t config;
    cache_.init(new cache_t(serializer, config, &get_global_perfmon_collection()));

    // SAMRSI: Pass the disk_ack_signal as a parameter?
    sync_callback_t disk_ack_signal;

    {
        transaction_t txn(cache_.get(), rwi_write, 1, repli_timestamp_t::invalid, order_token_t::ignore, &disk_ack_signal);
        // Hold the size block during writes, to lock out other writers.
        buf_lock_t z(&txn, 0, rwi_write);
        int64_t *p = static_cast<int64_t *>(z.get_data_write());
        *p = 0;
        for (block_id_t i = 1; i < MAX_BLOCK_ID && cache_->contains_block(i); ++i) {
            buf_lock_t b(&txn, i, rwi_write);
            b.mark_deleted();
        }
    }

    // SAMRSI: Wait here?
    disk_ack_signal.wait();
}

serializer_file_write_stream_t::~serializer_file_write_stream_t() { }

MUST_USE int64_t serializer_file_write_stream_t::write(const void *p, int64_t n) {
    const char *chp = static_cast<const char *>(p);
    const int block_size = cache_->get_block_size().value();

    // SAMRSI: Construct a disk_ack_signal here?  As a parameter?  (No, we can't.)  Wait on the
    // signal?  Construct and wait on the disk ack signal as configured by a boolean parameter
    // to the serializer_file_write_stream constructor?
    sync_callback_t disk_ack_signal;

    transaction_t txn(cache_.get(), rwi_write, 2 + n / block_size, repli_timestamp_t::invalid, order_token_t::ignore, &disk_ack_signal);
    // Hold the size block during writes, to lock out other writers.
    buf_lock_t z(&txn, 0, rwi_write);
    int64_t *const size_ptr = static_cast<int64_t *>(z.get_data_write());
    guarantee(*size_ptr == size_);
    int64_t offset = size_ + sizeof(int64_t);
    const int64_t end_offset = offset + n;
    while (offset < end_offset) {
        int64_t block_id = offset / block_size;
        guarantee(block_id <= MAX_BLOCK_ID);
        if (block_id >= MAX_BLOCK_ID) {
            return -1;
        }

        buf_lock_t block;
        buf_lock_t *b = &z;
        if (block_id > 0) {
            buf_lock_t tmp(&txn, block_id, rwi_write);
            block.swap(tmp);
            b = █
        }

        const int64_t block_offset = offset % block_size;
        const int64_t end_block_offset = end_offset / block_size == block_id ? end_offset % block_size : block_size;
        char *const buf = static_cast<char *>(b->get_data_write());
        const int64_t num_written = end_block_offset - block_offset;
        guarantee(num_written > 0);
        memcpy(buf + block_offset, chp, num_written);
        offset += num_written;
    }
    size_ += n;
    *size_ptr = size_;
    return n;
}

}  // namespace mock
<commit_msg>Handled a couple how-to-construct-the-transaction disk_ack_signals in serializer_filestream.cc.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "mock/serializer_filestream.hpp"

#include "buffer_cache/buffer_cache.hpp"
#include "perfmon/core.hpp"

namespace mock {

// Maybe we should have just used a blob for this.

serializer_file_read_stream_t::serializer_file_read_stream_t(serializer_t *serializer)
    : known_size_(-1), position_(0) {
    mirrored_cache_config_t config;
    cache_.init(new cache_t(serializer, config, &get_global_perfmon_collection()));
    if (cache_->contains_block(0)) {
        transaction_t txn(cache_.get(), rwi_read, order_token_t::ignore);
        buf_lock_t bufzero(&txn, 0, rwi_read);
        const void *data = bufzero.get_data_read();
        known_size_ = *static_cast<const int64_t *>(data);
        guarantee(known_size_ >= 0);
    }
}

serializer_file_read_stream_t::~serializer_file_read_stream_t() { }

MUST_USE int64_t serializer_file_read_stream_t::read(void *p, int64_t n) {
    if (known_size_ == -1) {
        return -1;
    }

    guarantee(n >= 0);
    const int64_t real_size = known_size_ + sizeof(int64_t);
    const int64_t real_position = position_ + sizeof(int64_t);

    if (real_position == real_size || n == 0) {
        return 0;
    }

    const block_size_t block_size = cache_->get_block_size();
    const int64_t block_number = real_position / block_size.value();
    const int64_t block_offset = real_position % block_size.value();

    const int64_t s = std::min(real_position + n, real_size);
    const int64_t end_block_offset = (s < block_size.value() * (block_number + 1)) ? s % block_size.value() : block_size.value();
    const int64_t num_copied = end_block_offset - block_offset;
    rassert(num_copied > 0);

    if (block_number >= MAX_BLOCK_ID) {
        return -1;
    }

    transaction_t txn(cache_.get(), rwi_read, order_token_t::ignore);
    buf_lock_t block(&txn, block_number, rwi_read);
    const char *data = static_cast<const char *>(block.get_data_read());
    memcpy(p, data + block_offset, num_copied);
    return num_copied;
}

serializer_file_write_stream_t::serializer_file_write_stream_t(serializer_t *serializer) : size_(0) {
    cache_t::create(serializer);
    mirrored_cache_config_t config;
    cache_.init(new cache_t(serializer, config, &get_global_perfmon_collection()));

    // SAMRSI: Pass the disk_ack_signal as a parameter?
    sync_callback_t disk_ack_signal;

    {
        transaction_t txn(cache_.get(), rwi_write, 1, repli_timestamp_t::invalid, order_token_t::ignore, &disk_ack_signal);
        // Hold the size block during writes, to lock out other writers.
        buf_lock_t z(&txn, 0, rwi_write);
        int64_t *p = static_cast<int64_t *>(z.get_data_write());
        *p = 0;
        for (block_id_t i = 1; i < MAX_BLOCK_ID && cache_->contains_block(i); ++i) {
            buf_lock_t b(&txn, i, rwi_write);
            b.mark_deleted();
        }
    }

    // SAMRSI: Wait here?
    disk_ack_signal.wait();
}

serializer_file_write_stream_t::~serializer_file_write_stream_t() { }

MUST_USE int64_t serializer_file_write_stream_t::write(const void *p, int64_t n) {
    const char *chp = static_cast<const char *>(p);
    const int block_size = cache_->get_block_size().value();

    // SAMRSI: Construct a disk_ack_signal here?  As a parameter?  (No, we can't.)  Wait on the
    // signal?  Construct and wait on the disk ack signal as configured by a boolean parameter
    // to the serializer_file_write_stream constructor?
    sync_callback_t disk_ack_signal;

    transaction_t txn(cache_.get(), rwi_write, 2 + n / block_size, repli_timestamp_t::invalid, order_token_t::ignore, &disk_ack_signal);
    // Hold the size block during writes, to lock out other writers.
    buf_lock_t z(&txn, 0, rwi_write);
    int64_t *const size_ptr = static_cast<int64_t *>(z.get_data_write());
    guarantee(*size_ptr == size_);
    int64_t offset = size_ + sizeof(int64_t);
    const int64_t end_offset = offset + n;
    while (offset < end_offset) {
        int64_t block_id = offset / block_size;
        guarantee(block_id <= MAX_BLOCK_ID);
        if (block_id >= MAX_BLOCK_ID) {
            return -1;
        }

        buf_lock_t block;
        buf_lock_t *b = &z;
        if (block_id > 0) {
            buf_lock_t tmp(&txn, block_id, rwi_write);
            block.swap(tmp);
            b = █
        }

        const int64_t block_offset = offset % block_size;
        const int64_t end_block_offset = end_offset / block_size == block_id ? end_offset % block_size : block_size;
        char *const buf = static_cast<char *>(b->get_data_write());
        const int64_t num_written = end_block_offset - block_offset;
        guarantee(num_written > 0);
        memcpy(buf + block_offset, chp, num_written);
        offset += num_written;
    }
    size_ += n;
    *size_ptr = size_;
    return n;
}

}  // namespace mock
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/xnnpack/reduce_tester.h"

#include <array>
#include <cstdint>
#include <functional>
#include <numeric>
#include <random>
#include <vector>

#include <gtest/gtest.h>
#include "flatbuffers/flatbuffers.h"  // from @flatbuffers
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/version.h"

namespace tflite {
namespace xnnpack {

void ReduceTester::Test(tflite::BuiltinOperator reduce_op,
                        TfLiteDelegate* delegate) const {
  std::random_device random_device;
  auto rng = std::mt19937(random_device());
  auto input_rng = std::bind(
      std::uniform_real_distribution<float>(-15.0f, 15.0f), std::ref(rng));

  std::vector<char> buffer = CreateTfLiteModel(reduce_op);
  const Model* model = GetModel(buffer.data());

  std::unique_ptr<Interpreter> delegate_interpreter;
  ASSERT_EQ(
      InterpreterBuilder(model, ::tflite::ops::builtin::BuiltinOpResolver())(
          &delegate_interpreter),
      kTfLiteOk);
  std::unique_ptr<Interpreter> default_interpreter;
  ASSERT_EQ(
      InterpreterBuilder(model, ::tflite::ops::builtin::BuiltinOpResolver())(
          &default_interpreter),
      kTfLiteOk);

  ASSERT_TRUE(delegate_interpreter);
  ASSERT_TRUE(default_interpreter);

  ASSERT_EQ(delegate_interpreter->inputs().size(), 1);
  ASSERT_EQ(default_interpreter->inputs().size(), 1);

  ASSERT_EQ(delegate_interpreter->outputs().size(), 1);
  ASSERT_EQ(default_interpreter->outputs().size(), 1);

  ASSERT_EQ(delegate_interpreter->AllocateTensors(), kTfLiteOk);
  ASSERT_EQ(default_interpreter->AllocateTensors(), kTfLiteOk);

  ASSERT_EQ(delegate_interpreter->ModifyGraphWithDelegate(delegate), kTfLiteOk);

  float* default_input_data = default_interpreter->typed_tensor<float>(
      default_interpreter->inputs()[0]);
  std::generate(default_input_data, default_input_data + InputSize(),
                std::ref(input_rng));

  float* delegate_input_data = delegate_interpreter->typed_tensor<float>(
      delegate_interpreter->inputs()[0]);
  std::copy(default_input_data, default_input_data + InputSize(),
            delegate_input_data);

  ASSERT_EQ(default_interpreter->Invoke(), kTfLiteOk);
  ASSERT_EQ(delegate_interpreter->Invoke(), kTfLiteOk);

  float* default_output_data = default_interpreter->typed_tensor<float>(
      default_interpreter->outputs()[0]);
  float* delegate_output_data = delegate_interpreter->typed_tensor<float>(
      delegate_interpreter->outputs()[0]);

  const int32_t output_size = OutputSize();
  for (size_t i = 0; i < output_size; i++) {
    ASSERT_NEAR(
        default_output_data[i], delegate_output_data[i],
        std::numeric_limits<float>::epsilon() *
            std::max(std::abs(default_output_data[i]) * RelativeTolerance(),
                     1.0f));
  }
}

std::vector<char> ReduceTester::CreateTfLiteModel(
    tflite::BuiltinOperator reduce_op) const {
  flatbuffers::FlatBufferBuilder builder;
  flatbuffers::Offset<OperatorCode> operator_code =
      CreateOperatorCode(builder, reduce_op);

  const std::array<flatbuffers::Offset<Buffer>, 2> buffers{{
      CreateBuffer(builder, builder.CreateVector({})),
      CreateBuffer(builder, builder.CreateVector(
                                reinterpret_cast<const uint8_t*>(Axes().data()),
                                sizeof(int32_t) * Axes().size())),
  }};

  const std::vector<int32_t> output_shape = OutputShape();
  const std::array<int32_t, 1> axes_shape{
      {static_cast<int32_t>(Axes().size())}};
  const std::array<flatbuffers::Offset<Tensor>, 3> tensors{{
      CreateTensor(builder,
                   builder.CreateVector<int32_t>(InputShape().data(),
                                                 InputShape().size()),
                   TensorType_FLOAT32),
      CreateTensor(
          builder,
          builder.CreateVector<int32_t>(axes_shape.data(), axes_shape.size()),
          TensorType_INT32, /*buffer=*/1),
      CreateTensor(builder,
                   builder.CreateVector<int32_t>(output_shape.data(),
                                                 output_shape.size()),
                   TensorType_FLOAT32),
  }};

  const flatbuffers::Offset<ReducerOptions> reducer_options =
      CreateReducerOptions(builder, KeepDims());

  const std::array<int32_t, 2> op_inputs{{0, 1}};
  const std::array<int32_t, 1> op_outputs{{2}};
  flatbuffers::Offset<Operator> op = CreateOperator(
      builder, /*opcode_index=*/0,
      builder.CreateVector<int32_t>(op_inputs.data(), op_inputs.size()),
      builder.CreateVector<int32_t>(op_outputs.data(), op_outputs.size()),
      tflite::BuiltinOptions_ReducerOptions, reducer_options.Union());

  const std::array<int32_t, 1> subgraph_inputs{{0}};
  const std::array<int32_t, 1> subgraph_outputs{{2}};
  flatbuffers::Offset<SubGraph> subgraph = CreateSubGraph(
      builder, builder.CreateVector(tensors.data(), tensors.size()),
      builder.CreateVector<int32_t>(subgraph_inputs.data(),
                                    subgraph_inputs.size()),
      builder.CreateVector<int32_t>(subgraph_outputs.data(),
                                    subgraph_outputs.size()),
      builder.CreateVector(&op, 1));

  flatbuffers::Offset<flatbuffers::String> description =
      builder.CreateString("Reduce model");

  flatbuffers::Offset<Model> model_buffer = CreateModel(
      builder, TFLITE_SCHEMA_VERSION, builder.CreateVector(&operator_code, 1),
      builder.CreateVector(&subgraph, 1), description,
      builder.CreateVector(buffers.data(), buffers.size()));

  builder.Finish(model_buffer);

  return std::vector<char>(builder.GetBufferPointer(),
                           builder.GetBufferPointer() + builder.GetSize());
}

int32_t ReduceTester::ComputeSize(const std::vector<int32_t>& shape) {
  return std::accumulate(shape.cbegin(), shape.cend(), 1,
                         std::multiplies<int32_t>());
}

}  // namespace xnnpack
}  // namespace tflite
<commit_msg>Avoid numerical stability issues in MEAN test<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/xnnpack/reduce_tester.h"

#include <array>
#include <cstdint>
#include <functional>
#include <numeric>
#include <random>
#include <vector>

#include <gtest/gtest.h>
#include "flatbuffers/flatbuffers.h"  // from @flatbuffers
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/version.h"

namespace tflite {
namespace xnnpack {

void ReduceTester::Test(tflite::BuiltinOperator reduce_op,
                        TfLiteDelegate* delegate) const {
  std::random_device random_device;
  auto rng = std::mt19937(random_device());
  auto input_rng =
      std::bind(std::uniform_real_distribution<float>(), std::ref(rng));

  std::vector<char> buffer = CreateTfLiteModel(reduce_op);
  const Model* model = GetModel(buffer.data());

  std::unique_ptr<Interpreter> delegate_interpreter;
  ASSERT_EQ(
      InterpreterBuilder(model, ::tflite::ops::builtin::BuiltinOpResolver())(
          &delegate_interpreter),
      kTfLiteOk);
  std::unique_ptr<Interpreter> default_interpreter;
  ASSERT_EQ(
      InterpreterBuilder(model, ::tflite::ops::builtin::BuiltinOpResolver())(
          &default_interpreter),
      kTfLiteOk);

  ASSERT_TRUE(delegate_interpreter);
  ASSERT_TRUE(default_interpreter);

  ASSERT_EQ(delegate_interpreter->inputs().size(), 1);
  ASSERT_EQ(default_interpreter->inputs().size(), 1);

  ASSERT_EQ(delegate_interpreter->outputs().size(), 1);
  ASSERT_EQ(default_interpreter->outputs().size(), 1);

  ASSERT_EQ(delegate_interpreter->AllocateTensors(), kTfLiteOk);
  ASSERT_EQ(default_interpreter->AllocateTensors(), kTfLiteOk);

  ASSERT_EQ(delegate_interpreter->ModifyGraphWithDelegate(delegate), kTfLiteOk);

  float* default_input_data = default_interpreter->typed_tensor<float>(
      default_interpreter->inputs()[0]);
  std::generate(default_input_data, default_input_data + InputSize(),
                std::ref(input_rng));

  float* delegate_input_data = delegate_interpreter->typed_tensor<float>(
      delegate_interpreter->inputs()[0]);
  std::copy(default_input_data, default_input_data + InputSize(),
            delegate_input_data);

  ASSERT_EQ(default_interpreter->Invoke(), kTfLiteOk);
  ASSERT_EQ(delegate_interpreter->Invoke(), kTfLiteOk);

  float* default_output_data = default_interpreter->typed_tensor<float>(
      default_interpreter->outputs()[0]);
  float* delegate_output_data = delegate_interpreter->typed_tensor<float>(
      delegate_interpreter->outputs()[0]);

  const int32_t output_size = OutputSize();
  for (size_t i = 0; i < output_size; i++) {
    ASSERT_NEAR(
        default_output_data[i], delegate_output_data[i],
        std::numeric_limits<float>::epsilon() *
            std::max(std::abs(default_output_data[i]) * RelativeTolerance(),
                     1.0f));
  }
}

std::vector<char> ReduceTester::CreateTfLiteModel(
    tflite::BuiltinOperator reduce_op) const {
  flatbuffers::FlatBufferBuilder builder;
  flatbuffers::Offset<OperatorCode> operator_code =
      CreateOperatorCode(builder, reduce_op);

  const std::array<flatbuffers::Offset<Buffer>, 2> buffers{{
      CreateBuffer(builder, builder.CreateVector({})),
      CreateBuffer(builder, builder.CreateVector(
                                reinterpret_cast<const uint8_t*>(Axes().data()),
                                sizeof(int32_t) * Axes().size())),
  }};

  const std::vector<int32_t> output_shape = OutputShape();
  const std::array<int32_t, 1> axes_shape{
      {static_cast<int32_t>(Axes().size())}};
  const std::array<flatbuffers::Offset<Tensor>, 3> tensors{{
      CreateTensor(builder,
                   builder.CreateVector<int32_t>(InputShape().data(),
                                                 InputShape().size()),
                   TensorType_FLOAT32),
      CreateTensor(
          builder,
          builder.CreateVector<int32_t>(axes_shape.data(), axes_shape.size()),
          TensorType_INT32, /*buffer=*/1),
      CreateTensor(builder,
                   builder.CreateVector<int32_t>(output_shape.data(),
                                                 output_shape.size()),
                   TensorType_FLOAT32),
  }};

  const flatbuffers::Offset<ReducerOptions> reducer_options =
      CreateReducerOptions(builder, KeepDims());

  const std::array<int32_t, 2> op_inputs{{0, 1}};
  const std::array<int32_t, 1> op_outputs{{2}};
  flatbuffers::Offset<Operator> op = CreateOperator(
      builder, /*opcode_index=*/0,
      builder.CreateVector<int32_t>(op_inputs.data(), op_inputs.size()),
      builder.CreateVector<int32_t>(op_outputs.data(), op_outputs.size()),
      tflite::BuiltinOptions_ReducerOptions, reducer_options.Union());

  const std::array<int32_t, 1> subgraph_inputs{{0}};
  const std::array<int32_t, 1> subgraph_outputs{{2}};
  flatbuffers::Offset<SubGraph> subgraph = CreateSubGraph(
      builder, builder.CreateVector(tensors.data(), tensors.size()),
      builder.CreateVector<int32_t>(subgraph_inputs.data(),
                                    subgraph_inputs.size()),
      builder.CreateVector<int32_t>(subgraph_outputs.data(),
                                    subgraph_outputs.size()),
      builder.CreateVector(&op, 1));

  flatbuffers::Offset<flatbuffers::String> description =
      builder.CreateString("Reduce model");

  flatbuffers::Offset<Model> model_buffer = CreateModel(
      builder, TFLITE_SCHEMA_VERSION, builder.CreateVector(&operator_code, 1),
      builder.CreateVector(&subgraph, 1), description,
      builder.CreateVector(buffers.data(), buffers.size()));

  builder.Finish(model_buffer);

  return std::vector<char>(builder.GetBufferPointer(),
                           builder.GetBufferPointer() + builder.GetSize());
}

int32_t ReduceTester::ComputeSize(const std::vector<int32_t>& shape) {
  return std::accumulate(shape.cbegin(), shape.cend(), 1,
                         std::multiplies<int32_t>());
}

}  // namespace xnnpack
}  // namespace tflite
<|endoftext|>