<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/utils.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

// stl
#include <algorithm>
#include <stdexcept>
#include <cstdlib>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#include FT_MODULE_H
}

void* _Alloc_Func(FT_Memory memory, long size)
{
    return std::malloc(size);
}

void _Free_Func(FT_Memory memory, void *block)
{
    std::free(block);
}

void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block)
{
    return std::realloc(block, new_size);
}

namespace mapnik
{

void init_freetype(FT_Memory memory, FT_Library & library)
{
    memory->alloc = _Alloc_Func;
    memory->free = _Free_Func;
    memory->realloc = _Realloc_Func;
    FT_Error error = FT_New_Library(memory, &library );
    if (error) throw std::runtime_error("can not initalise FreeType2 library");
    FT_Add_Default_Modules(library);
}

freetype_engine::freetype_engine()
    : library_(nullptr),
      memory_(new FT_MemoryRec_)
{
    init_freetype(&*memory_, library_);
}

freetype_engine::~freetype_engine()
{
    FT_Done_Library(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    // only accept files that will be matched by freetype2's `figurefiletype()`
    std::string fn = file_name;
    std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".woff"))||
        // Plus OSX custom ext
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count)
{
    if (count <= 0) return 0;
    FILE * file = static_cast<FILE *>(stream->descriptor.pointer);
    fseek (file , offset , SEEK_SET);
    return fread ((char*)buffer, 1, count, file);
}

void ft_close_cb(FT_Stream stream)
{
    fclose (static_cast<FILE *>(stream->descriptor.pointer));
}

bool freetype_engine::register_font(std::string const& file_name)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif

    FT_Library library = 0;
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    init_freetype(&*memory, library);
    bool result = register_font_impl(file_name, library);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library)
{
#ifdef _WINDOWS
    FILE * file = fopen(mapnik::utf8_to_utf16(file_name).c_str(),"rb");
#else
    FILE * file = fopen(file_name.c_str(),"rb");
#endif
    if (file == nullptr) return false;
    FT_Face face = 0;
    FT_Open_Args args;
    FT_StreamRec streamRec;
    memset(&args, 0, sizeof(args));
    memset(&streamRec, 0, sizeof(streamRec));
    fseek(file, 0, SEEK_END);
    std::size_t file_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    streamRec.base = 0;
    streamRec.pos = 0;
    streamRec.size = file_size;
    streamRec.descriptor.pointer = file;
    streamRec.read  = ft_read_cb;
    streamRec.close = ft_close_cb;
    args.flags = FT_OPEN_STREAM;
    args.stream = &streamRec;
    int num_faces = 0;
    bool success = false;
    // some font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < num_faces; i++ ) {
        // if face is null then this is the first face
        FT_Error error = FT_Open_Face(library, &args, i, &face);
        if (error)
        {
            break;
        }
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (!num_faces)
            num_faces = face->num_faces;
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            s << "Warning: unable to load font file '" << file_name << "' ";
            if (!face->family_name && !face->style_name)
                s << "which lacks both a family name and style name";
            else if (face->family_name)
                s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name";
            else if (face->style_name)
                s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
    }

    if (face) FT_Done_Face(face);

    return success;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_fonts_impl(dir, library, recurse);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return mapnik::freetype_engine::register_font_impl(dir, library);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
#ifdef _WINDOWS
        std::wstring wide_dir(mapnik::utf8_to_utf16(dir));
        for (boost::filesystem::directory_iterator itr(wide_dir); itr != end_itr; ++itr)
        {
    #if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = mapnik::utf16_to_utf8(itr->path().wstring());
    #else // v2
            std::string file_name = mapnik::utf16_to_utf8(itr->wstring());
    #endif
#else
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = itr->path().string();
#else // v2
            std::string file_name = itr->string();
#endif
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts_impl(file_name, library, true))
                {
                    success = true;
                }
            }
            else
            {
#if (BOOST_FILESYSTEM_VERSION == 3)
                std::string base_name = itr->path().filename().string();
#else // v2
                std::string base_name = itr->filename();
#endif
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (mapnik::freetype_engine::register_font_impl(file_name, library))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    for (auto const& kv : name2file_)
    {
        names.push_back(kv.first);
    }
    return names;
}

std::map<std::string,std::pair<int,std::string> > const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    auto itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;

        auto mem_font_itr = memory_fonts_.find(itr->second.second);

        if (mem_font_itr != memory_fonts_.end()) // memory font
        {
            FT_Error error = FT_New_Memory_Face(library_,
                                                reinterpret_cast<FT_Byte const*>(mem_font_itr->second.c_str()),
                                                static_cast<FT_Long>(mem_font_itr->second.size()), // size
                                                itr->second.first, // face index
                                                &face);

            if (!error) return std::make_shared<font_face>(face);
        }
        else
        {
            // load font into memory
#ifdef MAPNIK_THREADSAFE
            mapnik::scoped_lock lock(mutex_);
#endif
            FILE * file = fopen(itr->second.second.c_str(),"rb");
            if (file != nullptr)
            {
                fseek(file, 0, SEEK_END);
                unsigned long file_size = ftell(file);
                fseek(file, 0, SEEK_SET);
                boost::scoped_array<char> buffer(new char[file_size]);
                fread(buffer.get(), 1, file_size, file);
                auto result = memory_fonts_.insert(std::make_pair(itr->second.second, std::string(buffer.get())));

                FT_Error error = FT_New_Memory_Face (library_,
                                                     reinterpret_cast<FT_Byte const*>(result.first->second.c_str()),
                                                     static_cast<FT_Long>(result.first->second.size()),
                                                     itr->second.first,
                                                     &face);
                if (!error) return std::make_shared<font_face>(face);
                else
                {
                    // we can't load font, erase it.
                    memory_fonts_.erase(result.first);
                }
            }
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return std::make_shared<stroker>(s);
    }
    return stroker_ptr();
}

template <typename T>
face_ptr face_manager<T>::get_face(std::string const& name)
{
    auto itr = face_ptr_cache_.find(name);
    if (itr != face_ptr_cache_.end())
    {
        return itr->second;
    }
    else
    {
        face_ptr face = engine_.create_face(name);
        if (face)
        {
            face_ptr_cache_.insert(make_pair(name,face));
        }
        return face;
    }
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(std::string const& name)
{
    face_set_ptr face_set = std::make_shared<font_face_set>();
    if (face_ptr face = get_face(name))
    {
        face_set->add(face);
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(font_set const& fset)
{
    std::vector<std::string> const& names = fset.get_face_names();
    face_set_ptr face_set = std::make_shared<font_face_set>();
    for (auto const& name  : names)
    {
        face_ptr face = get_face(name);
        if (face)
        {
            face_set->add(face);
        }
#ifdef MAPNIK_LOG
        else
        {
            MAPNIK_LOG_DEBUG(font_engine_freetype)
                << "Failed to find face '" << name
                << "' in font set '" << fset.get_name() << "'\n";
        }
#endif
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const std::string &name, boost::optional<font_set> fset)
{
    if (fset && fset->size() > 0)
    {
        return get_face_set(*fset);
    }
    else
    {
        return get_face_set(name);
    }
}

#ifdef MAPNIK_THREADSAFE
std::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
std::map<std::string,std::string> freetype_engine::memory_fonts_;
template class face_manager<freetype_engine>;

}
<commit_msg>oops buffer.get() returns raw bytes (not `\0` terminated C-string)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/utils.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

// stl
#include <algorithm>
#include <stdexcept>
#include <cstdlib>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#include FT_MODULE_H
}

void* _Alloc_Func(FT_Memory memory, long size)
{
    return std::malloc(size);
}

void _Free_Func(FT_Memory memory, void *block)
{
    std::free(block);
}

void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block)
{
    return std::realloc(block, new_size);
}

namespace mapnik
{

void init_freetype(FT_Memory memory, FT_Library & library)
{
    memory->alloc = _Alloc_Func;
    memory->free = _Free_Func;
    memory->realloc = _Realloc_Func;
    FT_Error error = FT_New_Library(memory, &library );
    if (error) throw std::runtime_error("can not initalise FreeType2 library");
    FT_Add_Default_Modules(library);
}

freetype_engine::freetype_engine()
    : library_(nullptr),
      memory_(new FT_MemoryRec_)
{
    init_freetype(&*memory_, library_);
}

freetype_engine::~freetype_engine()
{
    FT_Done_Library(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    // only accept files that will be matched by freetype2's `figurefiletype()`
    std::string fn = file_name;
    std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".woff"))||
        // Plus OSX custom ext
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count)
{
    if (count <= 0) return 0;
    FILE * file = static_cast<FILE *>(stream->descriptor.pointer);
    fseek (file , offset , SEEK_SET);
    return fread ((char*)buffer, 1, count, file);
}

void ft_close_cb(FT_Stream stream)
{
    fclose (static_cast<FILE *>(stream->descriptor.pointer));
}

bool freetype_engine::register_font(std::string const& file_name)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif

    FT_Library library = 0;
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    init_freetype(&*memory, library);
    bool result = register_font_impl(file_name, library);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library)
{
#ifdef _WINDOWS
    FILE * file = fopen(mapnik::utf8_to_utf16(file_name).c_str(),"rb");
#else
    FILE * file = fopen(file_name.c_str(),"rb");
#endif
    if (file == nullptr) return false;
    FT_Face face = 0;
    FT_Open_Args args;
    FT_StreamRec streamRec;
    memset(&args, 0, sizeof(args));
    memset(&streamRec, 0, sizeof(streamRec));
    fseek(file, 0, SEEK_END);
    std::size_t file_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    streamRec.base = 0;
    streamRec.pos = 0;
    streamRec.size = file_size;
    streamRec.descriptor.pointer = file;
    streamRec.read  = ft_read_cb;
    streamRec.close = ft_close_cb;
    args.flags = FT_OPEN_STREAM;
    args.stream = &streamRec;
    int num_faces = 0;
    bool success = false;
    // some font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < num_faces; i++ ) {
        // if face is null then this is the first face
        FT_Error error = FT_Open_Face(library, &args, i, &face);
        if (error)
        {
            break;
        }
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (!num_faces)
            num_faces = face->num_faces;
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            s << "Warning: unable to load font file '" << file_name << "' ";
            if (!face->family_name && !face->style_name)
                s << "which lacks both a family name and style name";
            else if (face->family_name)
                s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name";
            else if (face->style_name)
                s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
    }

    if (face) FT_Done_Face(face);

    return success;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_fonts_impl(dir, library, recurse);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return mapnik::freetype_engine::register_font_impl(dir, library);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
#ifdef _WINDOWS
        std::wstring wide_dir(mapnik::utf8_to_utf16(dir));
        for (boost::filesystem::directory_iterator itr(wide_dir); itr != end_itr; ++itr)
        {
    #if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = mapnik::utf16_to_utf8(itr->path().wstring());
    #else // v2
            std::string file_name = mapnik::utf16_to_utf8(itr->wstring());
    #endif
#else
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = itr->path().string();
#else // v2
            std::string file_name = itr->string();
#endif
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts_impl(file_name, library, true))
                {
                    success = true;
                }
            }
            else
            {
#if (BOOST_FILESYSTEM_VERSION == 3)
                std::string base_name = itr->path().filename().string();
#else // v2
                std::string base_name = itr->filename();
#endif
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (mapnik::freetype_engine::register_font_impl(file_name, library))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    for (auto const& kv : name2file_)
    {
        names.push_back(kv.first);
    }
    return names;
}

std::map<std::string,std::pair<int,std::string> > const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    auto itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;

        auto mem_font_itr = memory_fonts_.find(itr->second.second);

        if (mem_font_itr != memory_fonts_.end()) // memory font
        {
            FT_Error error = FT_New_Memory_Face(library_,
                                                reinterpret_cast<FT_Byte const*>(mem_font_itr->second.c_str()),
                                                static_cast<FT_Long>(mem_font_itr->second.size()), // size
                                                itr->second.first, // face index
                                                &face);

            if (!error) return std::make_shared<font_face>(face);
        }
        else
        {
            // load font into memory
#ifdef MAPNIK_THREADSAFE
            mapnik::scoped_lock lock(mutex_);
#endif
            FILE * file = fopen(itr->second.second.c_str(),"rb");
            if (file != nullptr)
            {
                fseek(file, 0, SEEK_END);
                unsigned long file_size = ftell(file);
                fseek(file, 0, SEEK_SET);
                boost::scoped_array<char> buffer(new char[file_size]);
                fread(buffer.get(), 1, file_size, file);
                auto result = memory_fonts_.insert(std::make_pair(itr->second.second, std::string(buffer.get(),file_size)));

                FT_Error error = FT_New_Memory_Face (library_,
                                                     reinterpret_cast<FT_Byte const*>(result.first->second.c_str()),
                                                     static_cast<FT_Long>(result.first->second.size()),
                                                     itr->second.first,
                                                     &face);
                if (!error) return std::make_shared<font_face>(face);
                else
                {
                    // we can't load font, erase it.
                    memory_fonts_.erase(result.first);
                }
            }
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return std::make_shared<stroker>(s);
    }
    return stroker_ptr();
}

template <typename T>
face_ptr face_manager<T>::get_face(std::string const& name)
{
    auto itr = face_ptr_cache_.find(name);
    if (itr != face_ptr_cache_.end())
    {
        return itr->second;
    }
    else
    {
        face_ptr face = engine_.create_face(name);
        if (face)
        {
            face_ptr_cache_.insert(make_pair(name,face));
        }
        return face;
    }
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(std::string const& name)
{
    face_set_ptr face_set = std::make_shared<font_face_set>();
    if (face_ptr face = get_face(name))
    {
        face_set->add(face);
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(font_set const& fset)
{
    std::vector<std::string> const& names = fset.get_face_names();
    face_set_ptr face_set = std::make_shared<font_face_set>();
    for (auto const& name  : names)
    {
        face_ptr face = get_face(name);
        if (face)
        {
            face_set->add(face);
        }
#ifdef MAPNIK_LOG
        else
        {
            MAPNIK_LOG_DEBUG(font_engine_freetype)
                << "Failed to find face '" << name
                << "' in font set '" << fset.get_name() << "'\n";
        }
#endif
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const std::string &name, boost::optional<font_set> fset)
{
    if (fset && fset->size() > 0)
    {
        return get_face_set(*fset);
    }
    else
    {
        return get_face_set(name);
    }
}

#ifdef MAPNIK_THREADSAFE
std::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
std::map<std::string,std::string> freetype_engine::memory_fonts_;
template class face_manager<freetype_engine>;

}
<|endoftext|>


<commit_before>// $Id$
// Author: Akira Okumura 2012/11/26

// Examples for simple optical systems which use products by Edmund Optics.

// define useful units
static const Double_t cm = AOpticsManager::cm();
static const Double_t mm = AOpticsManager::mm();
static const Double_t um = AOpticsManager::um();
static const Double_t nm = AOpticsManager::nm();
static const Double_t  m = AOpticsManager::m();

void NT49665()
{
  // Aspherized achromatic lens.
  // http://www.edmundoptics.com/optics/optical-lenses/aspheric-lenses/aspherized-achromatic-lenses/2953

  AOpticsManager* manager = new AOpticsManager("NT49665", "NT49665");

  // Make the world
  TGeoBBox* box = new TGeoBBox("box", 10*cm, 10*cm, 10*cm);
  AOpticalComponent *top = new AOpticalComponent("top", box);
  manager->SetTopVolume(top);

  Double_t rmax = 12.5*mm;
  Double_t rmin =   0.*mm;

  Double_t d1 = 9.0*mm;
  Double_t d2 = 2.5*mm;
  Double_t d3 = 8e-2*mm;
  Double_t d4 = 4.40605264801e1*mm;

  Double_t z1 = 0*mm;
  Double_t z2 = z1 + d1;
  Double_t z3 = z2 + d2;
  Double_t z4 = z3 + d3;
  Double_t z5 = z4 + d4;

  Double_t curv1 = 1./(28.5*mm);
  Double_t curv2 = 1./(-31.0*mm);
  Double_t curv3 = 1./(-66.0*mm);
  Double_t curv4 = 1./(-63.0*mm);

  AGeoAsphericDisk* disk1
    = new AGeoAsphericDisk("disk1", z1, curv1, z2, curv2, rmax, rmin);
  AGeoAsphericDisk* disk2
    = new AGeoAsphericDisk("disk2", z2, curv2, z3, curv3, rmax, rmin);
  AGeoAsphericDisk* disk3
    = new AGeoAsphericDisk("disk3", z3, curv3, z4, curv4, rmax, rmin);
  Double_t coefficients[3] = {0, 4.66252900195e-6/(mm*mm*mm), -8.02842124899e-9/(mm*mm*mm*mm*mm)};
  //Double_t coefficients[3] = {4.66252900195e-6/(mm*mm), -8.02842124899e-9/(mm*mm*mm*mm), 0};
  disk3->SetPolynomials(0, 0, 3, coefficients);

  TGeoMaterial* dummyMaterial = new TGeoMaterial("dummyMaterial", 0, 0, 0);
  dummyMaterial->SetTransparency(70);
  TGeoMedium* dummyMedium = new TGeoMedium("dummyMedium", 1, dummyMaterial);

  // Ohara S-FSL5
  // http://www.ohara-inc.co.jp/jp/product/optical/dl/data/jsfsl05.pdf
  ASellmeierFormula* FSL5
    = new ASellmeierFormula(1.17447043e0,   1.40056154e-2, 1.19272435e0,
                            8.41855181e-3, -5.81790767e-2, 1.29599726e2);

  // should be 1.48749
  std::cout << FSL5->GetIndex(0.58756*um) << std::endl;

  // S-TIH13
  // http://www.ohara-inc.co.jp/jp/product/optical/dl/data/jstih13.pdf
  ASellmeierFormula* TIH13
    = new ASellmeierFormula(1.62224674e0, 2.93844589e-1, 1.99225164e0,
                            1.18368386e-2,5.90208025e-2, 1.71959976e2);

  // should be 1.74077
  std::cout << TIH13->GetIndex(0.58756*um) << std::endl;

  ALens* lens1 = new ALens("lens1", disk1, dummyMedium);
  lens1->SetRefractiveIndex(FSL5);
  ALens* lens2 = new ALens("lens2", disk2, dummyMedium);
  lens2->SetRefractiveIndex(TIH13);
  ALens* lens3 = new ALens("lens3", disk3, dummyMedium);
  lens3->SetConstantRefractiveIndex(1.517);

  top->AddNode(lens1, 1);
  top->AddNode(lens2, 1);
  top->AddNode(lens3, 1);

  Double_t origin[3] = {0, 0, z5 + 1*um};
  TGeoBBox* box2 = new TGeoBBox("box2", 1*mm, 1*mm, 1*um, origin);
  AFocalSurface* screen = new AFocalSurface("screen", box2);
  top->AddNode(screen, 1);

  manager->CloseGeometry();

  top->Draw("ogl");

  TGeoRotation* rot = new TGeoRotation;
  rot->SetAngles(180., 0., 0.);

  TGeoTranslation* tr = new TGeoTranslation("tr", 0, 0, -15*mm);

  const Int_t nColor = 3;
  Double_t wavelength[nColor] = {486.1*nm, 587.6*nm, 656.3*nm}; // n_F, n_d, n_C
  TH2D* spot[nColor];

  for(Int_t j = 0; j < nColor; j++){
    ARayArray* array = ARayShooter::Circle(wavelength[j], rmax*1.1, 50, 4, rot, tr);

    manager->TraceNonSequential(*array);

    spot[j] = new TH2D(Form("spot%d", j), Form("Spot Diagram for #it{#lambda} = %5.1f (nm);X (#it{#mu}m);Y (#it{#mu}m)", wavelength[j]/nm), 500, -25, 25, 500, -25, 25);

    TObjArray* focused = array->GetFocused();

    for(Int_t i = 0; i <= focused->GetLast(); i++){
      ARay* ray = (ARay*)(*focused)[i];
      if(j == 1 && i%10 == 0){
        ray->MakePolyLine3D()->Draw();
      } // if

      Double_t p[4];
      ray->GetLastPoint(p);

      spot[j]->Fill(p[0]/um, p[1]/um);
    } // i

    delete array;
  } // j

  TCanvas* can = new TCanvas("can", "can", 1200, 400);
  can->Divide(3, 1, 1e-10, 1e-10);

  for(Int_t j = 0; j < nColor; j++){
    can->cd(j + 1);
    spot[j]->Draw("colz");
  } // j

}
<commit_msg>Added the URL of the ZEMAX file<commit_after>// $Id$
// Author: Akira Okumura 2012/11/26

// Examples for simple optical systems which use products by Edmund Optics.

// define useful units
static const Double_t cm = AOpticsManager::cm();
static const Double_t mm = AOpticsManager::mm();
static const Double_t um = AOpticsManager::um();
static const Double_t nm = AOpticsManager::nm();
static const Double_t  m = AOpticsManager::m();

void NT49665()
{
  // Aspherized achromatic lens.
  // http://www.edmundoptics.com/optics/optical-lenses/aspheric-lenses/aspherized-achromatic-lenses/2953

  // ZEMAX data is available at
  // http://www.edmundoptics.jp/techsupport/resource_center/product_docs/zmax_49665.zmx

  AOpticsManager* manager = new AOpticsManager("NT49665", "NT49665");

  // Make the world
  TGeoBBox* box = new TGeoBBox("box", 10*cm, 10*cm, 10*cm);
  AOpticalComponent *top = new AOpticalComponent("top", box);
  manager->SetTopVolume(top);

  Double_t rmax = 12.5*mm;
  Double_t rmin =   0.*mm;

  Double_t d1 = 9.0*mm;
  Double_t d2 = 2.5*mm;
  Double_t d3 = 8e-2*mm;
  Double_t d4 = 4.40605264801e1*mm;

  Double_t z1 = 0*mm;
  Double_t z2 = z1 + d1;
  Double_t z3 = z2 + d2;
  Double_t z4 = z3 + d3;
  Double_t z5 = z4 + d4;

  Double_t curv1 = 1./(28.5*mm);
  Double_t curv2 = 1./(-31.0*mm);
  Double_t curv3 = 1./(-66.0*mm);
  Double_t curv4 = 1./(-63.0*mm);

  AGeoAsphericDisk* disk1
    = new AGeoAsphericDisk("disk1", z1, curv1, z2, curv2, rmax, rmin);
  AGeoAsphericDisk* disk2
    = new AGeoAsphericDisk("disk2", z2, curv2, z3, curv3, rmax, rmin);
  AGeoAsphericDisk* disk3
    = new AGeoAsphericDisk("disk3", z3, curv3, z4, curv4, rmax, rmin);
  Double_t coefficients[3] = {0, 4.66252900195e-6/(mm*mm*mm), -8.02842124899e-9/(mm*mm*mm*mm*mm)};
  //Double_t coefficients[3] = {4.66252900195e-6/(mm*mm), -8.02842124899e-9/(mm*mm*mm*mm), 0};
  disk3->SetPolynomials(0, 0, 3, coefficients);

  TGeoMaterial* dummyMaterial = new TGeoMaterial("dummyMaterial", 0, 0, 0);
  dummyMaterial->SetTransparency(70);
  TGeoMedium* dummyMedium = new TGeoMedium("dummyMedium", 1, dummyMaterial);

  // Ohara S-FSL5
  // http://www.ohara-inc.co.jp/jp/product/optical/dl/data/jsfsl05.pdf
  ASellmeierFormula* FSL5
    = new ASellmeierFormula(1.17447043e0,   1.40056154e-2, 1.19272435e0,
                            8.41855181e-3, -5.81790767e-2, 1.29599726e2);

  // should be 1.48749
  std::cout << FSL5->GetIndex(0.58756*um) << std::endl;

  // S-TIH13
  // http://www.ohara-inc.co.jp/jp/product/optical/dl/data/jstih13.pdf
  ASellmeierFormula* TIH13
    = new ASellmeierFormula(1.62224674e0, 2.93844589e-1, 1.99225164e0,
                            1.18368386e-2,5.90208025e-2, 1.71959976e2);

  // should be 1.74077
  std::cout << TIH13->GetIndex(0.58756*um) << std::endl;

  ALens* lens1 = new ALens("lens1", disk1, dummyMedium);
  lens1->SetRefractiveIndex(FSL5);
  ALens* lens2 = new ALens("lens2", disk2, dummyMedium);
  lens2->SetRefractiveIndex(TIH13);
  ALens* lens3 = new ALens("lens3", disk3, dummyMedium);
  lens3->SetConstantRefractiveIndex(1.517);

  top->AddNode(lens1, 1);
  top->AddNode(lens2, 1);
  top->AddNode(lens3, 1);

  Double_t origin[3] = {0, 0, z5 + 1*um};
  TGeoBBox* box2 = new TGeoBBox("box2", 1*mm, 1*mm, 1*um, origin);
  AFocalSurface* screen = new AFocalSurface("screen", box2);
  top->AddNode(screen, 1);

  manager->CloseGeometry();

  top->Draw("ogl");

  TGeoRotation* rot = new TGeoRotation;
  rot->SetAngles(180., 0., 0.);

  TGeoTranslation* tr = new TGeoTranslation("tr", 0, 0, -15*mm);

  const Int_t nColor = 3;
  Double_t wavelength[nColor] = {486.1*nm, 587.6*nm, 656.3*nm}; // n_F, n_d, n_C
  TH2D* spot[nColor];

  for(Int_t j = 0; j < nColor; j++){
    ARayArray* array = ARayShooter::Circle(wavelength[j], rmax*1.1, 50, 4, rot, tr);

    manager->TraceNonSequential(*array);

    spot[j] = new TH2D(Form("spot%d", j), Form("Spot Diagram for #it{#lambda} = %5.1f (nm);X (#it{#mu}m);Y (#it{#mu}m)", wavelength[j]/nm), 500, -25, 25, 500, -25, 25);

    TObjArray* focused = array->GetFocused();

    for(Int_t i = 0; i <= focused->GetLast(); i++){
      ARay* ray = (ARay*)(*focused)[i];
      if(j == 1 && i%10 == 0){
        ray->MakePolyLine3D()->Draw();
      } // if

      Double_t p[4];
      ray->GetLastPoint(p);

      spot[j]->Fill(p[0]/um, p[1]/um);
    } // i

    delete array;
  } // j

  TCanvas* can = new TCanvas("can", "can", 1200, 400);
  can->Divide(3, 1, 1e-10, 1e-10);

  for(Int_t j = 0; j < nColor; j++){
    can->cd(j + 1);
    spot[j]->Draw("colz");
  } // j

}
<|endoftext|>


<commit_before>//-----------------------------------------------------------
//
//    Copyright (C) 2015 - 2016 by the deal2lkit authors
//
//    This file is part of the deal2lkit library.
//
//    The deal2lkit library is free software; you can use it, redistribute
//    it, and/or modify it under the terms of the GNU Lesser General
//    Public License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//    The full text of the license can be found in the file LICENSE at
//    the top level of the deal2lkit distribution.
//
//-----------------------------------------------------------

#include <deal2lkit/parameter_acceptor.h>
#include <deal2lkit/utilities.h>
#include <deal.II/base/point.h>
#include <deal.II/base/revision.h>
#include <deal2lkit/revision.h>
#include <fstream>

D2K_NAMESPACE_OPEN

// Static empty class list
std::vector<SmartPointer<ParameterAcceptor> > ParameterAcceptor::class_list;
// Static parameter handler
ParameterHandler ParameterAcceptor::prm;

ParameterAcceptor::ParameterAcceptor(const std::string name) :
  acceptor_id(class_list.size()),
  section_name(name)
{
  SmartPointer<ParameterAcceptor> pt(this, type(*this).c_str());
  class_list.push_back(pt);
}

ParameterAcceptor::~ParameterAcceptor()
{
  class_list[acceptor_id] = 0;
}

std::string ParameterAcceptor::get_section_name() const
{
  return (section_name != "" ? section_name : type(*this));
}

void
ParameterAcceptor::initialize(const std::string filename,
                              const std::string out_filename)
{
  prm.clear();
  declare_all_parameters(prm);
  if (filename != "")
    {
      // check the extension of input file
      if (filename.substr(filename.find_last_of(".") + 1) == "prm")
        prm.read_input(filename);
      else if (filename.substr(filename.find_last_of(".") + 1) == "xml")
        {
          std::ifstream is(filename);
          prm.read_input_from_xml(is);
        }
      else
        AssertThrow(false, ExcMessage("Invalid extension of parameter file. Please use .prm or .xml"));
    }
  parse_all_parameters(prm);
  if (out_filename != "")
    {
      std::ofstream outfile(out_filename.c_str());
      Assert(outfile, ExcIO());
      std::string extension = out_filename.substr(out_filename.find_last_of(".") + 1);

      if ( extension == "prm")
        {
          outfile << "# Parameter file generated with " << std::endl
                  << "# D2K_GIT_BRANCH=       " << D2K_GIT_BRANCH << std::endl
                  << "# D2K_GIT_SHORTREV=     " << D2K_GIT_SHORTREV << std::endl
                  << "# DEAL_II_GIT_BRANCH=   " << DEAL_II_GIT_BRANCH  << std::endl
                  << "# DEAL_II_GIT_SHORTREV= " << DEAL_II_GIT_SHORTREV << std::endl;
          prm.print_parameters(outfile, ParameterHandler::ShortText);
        }
      else if (extension == "xml")
        prm.print_parameters(outfile, ParameterHandler::XML);
      else if (extension == "latex" || extension == "tex")
        prm.print_parameters(outfile, ParameterHandler::LaTeX);
      else
        AssertThrow(false,ExcNotImplemented());
    }
}

void
ParameterAcceptor::clear()
{
  class_list.clear();
}

void
ParameterAcceptor::log_info()
{
  deallog.push("ParameterAcceptor");
  for (unsigned int i=0; i<class_list.size(); ++i)
    {
      deallog << "Class " << i << ":";
      if (class_list[i])
        deallog << class_list[i]->get_section_name() << std::endl;
      else
        deallog << " NULL" << std::endl;
    }
  deallog.pop();
}

void ParameterAcceptor::parse_all_parameters(ParameterHandler &prm)
{
  std::vector<std::string> old_secs;
  for (unsigned int i=0; i< class_list.size(); ++i)
    if (class_list[i] != NULL)
      {
        std::vector<std::string> secs;
        secs = Utilities::split_string_list(class_list[i]->get_section_name(), sep);
        const unsigned int secs_size = secs.size();

        if (secs_size == 1) // add a subsection with relative path
          {
            // enter the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.enter_subsection(old_secs[s]);

            // enter current subsection
            prm.enter_subsection(secs[0]);

            class_list[i]->parse_parameters(prm);
            class_list[i]->parse_parameters_call_back();

            // leave current subsection
            prm.leave_subsection();

            // leave the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.leave_subsection();

            // the old path is unchanged
          }

        else // we have at least one separator "/"
          {
            if (secs[0]=="") // the section name begins with "/"
              {
                // first of all remove the "empty" section
                secs.erase(secs.begin());

                // this means absolute path so we do not enter
                // the old path
                for (unsigned int s=0; s<secs.size(); ++s)
                  prm.enter_subsection(secs[s]);

                class_list[i]->parse_parameters(prm);
                class_list[i]->parse_parameters_call_back();

                // leave all the current sections
                for (unsigned int s=0; s<secs.size(); ++s)
                  prm.leave_subsection();

                // since we have started from the root section i.e. "/"
                // we need to set the old path to the current one
                // without the last subsection

                // remove the last subsection
                secs.pop_back();

                // update the old path
                old_secs.swap(secs);

              }
            else // append the path to the old path
              {
                // enter the old path
                for (unsigned int s=0; s<old_secs.size(); ++s)
                  prm.enter_subsection(old_secs[s]);

                // new path
                for (unsigned int s=0; s<secs.size(); ++s)
                  prm.enter_subsection(secs[s]);

                class_list[i]->parse_parameters(prm);
                class_list[i]->parse_parameters_call_back();

                // leave all subsections
                for (unsigned int s=0; s<(secs.size()+old_secs.size()); ++s)
                  prm.leave_subsection();

                // we need now to append the secs path (without the last subsection)
                // to the old path

                // remove last subsection
                secs.pop_back();

                // append secs to old_secs
                old_secs.insert(old_secs.begin(), secs.begin(), secs.end());

              }
          }
      }
}

void ParameterAcceptor::declare_all_parameters(ParameterHandler &prm)
{
  std::vector<std::string> old_secs;
  for (unsigned int i=0; i< class_list.size(); ++i)
    if (class_list[i] != NULL)
      {
        std::vector<std::string> secs;
        secs = Utilities::split_string_list(class_list[i]->get_section_name(), sep);
        const unsigned int secs_size = secs.size();

        if (secs_size == 1) // add a subsection with relative path
          {
            // enter the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.enter_subsection(old_secs[s]);

            // enter current subsection
            prm.enter_subsection(secs[0]);

            class_list[i]->declare_parameters(prm);

            // leave current subsection
            prm.leave_subsection();

            // leave the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.leave_subsection();

            // the old path is unchanged
          }

        else // we have at least one separator "/"
          {
            for (unsigned int s=0; s <secs.size(); ++s)
              if (secs[0]=="") // the section name begins with "/"
                {
                  // first of all remove the "empty" section
                  secs.erase(secs.begin());

                  // this means absolute path so we do not enter
                  // the old path
                  for (unsigned int s=0; s<secs.size(); ++s)
                    prm.enter_subsection(secs[s]);

                  class_list[i]->declare_parameters(prm);

                  // leave all the current sections
                  for (unsigned int s=0; s<secs.size(); ++s)
                    prm.leave_subsection();

                  // since we have started from the root section i.e. "/"
                  // we need to set the old path to the current one
                  // without the last subsection

                  // remove the last subsection
                  secs.pop_back();

                  // update the old path
                  old_secs.swap(secs);

                }
              else // append the path to the old path
                {
                  // enter the old path
                  for (unsigned int s=0; s<old_secs.size(); ++s)
                    prm.enter_subsection(old_secs[s]);

                  // new path
                  for (unsigned int s=0; s<secs.size(); ++s)
                    prm.enter_subsection(secs[s]);

                  class_list[i]->declare_parameters(prm);

                  // leave all subsections
                  for (unsigned int s=0; s<(secs.size()+old_secs.size()); ++s)
                    prm.leave_subsection();

                  // we need now to append the secs path (without the last subsection)
                  // to the old path

                  // remove last subsection
                  secs.pop_back();

                  // append secs to old_secs
                  old_secs.insert(old_secs.begin(), secs.begin(), secs.end());

                }
          }
      }
}

void ParameterAcceptor::parse_parameters(ParameterHandler &prm)
{
  for (auto it = parameters.begin(); it != parameters.end(); ++it)
    {
      if (it->second.type() == typeid(std::string *))
        {
          *(boost::any_cast<std::string *>(it->second)) = prm.get(it->first);
        }
      else if (it->second.type() == typeid(double *))
        {
          *(boost::any_cast<double *>(it->second)) = prm.get_double(it->first);
        }
      else if (it->second.type() == typeid(int *))
        {
          *(boost::any_cast<int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(unsigned int *))
        {
          *(boost::any_cast<unsigned int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(bool *))
        {
          *(boost::any_cast<bool *>(it->second)) = prm.get_bool(it->first);
        }
      // Here we have the difficult types...
      // First all point types.
      else if (it->second.type() == typeid(Point<1> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 1);

          Point<1> &pp = *(boost::any_cast<Point<1>*>(it->second));
          pp[0] = p[0];
        }
      else if (it->second.type() == typeid(Point<2> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 2);

          Point<2> &pp = *(boost::any_cast<Point<2>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
        }
      else if (it->second.type() == typeid(Point<3> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 3);

          Point<3> &pp = *(boost::any_cast<Point<3>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
          pp[2] = p[2];
        }
      else if (it->second.type() == typeid(std::vector<std::string> *))
        {
          std::vector<std::string> &string_list = *(boost::any_cast<std::vector<std::string>*>(it->second));
          string_list = Utilities::split_string_list(prm.get(it->first));
        }
      else if (it->second.type() == typeid(std::vector<unsigned int> *))
        {
          std::vector<unsigned int> &int_list = *(boost::any_cast<std::vector<unsigned int>*>(it->second));
          std::vector<std::string> string_list = Utilities::split_string_list(prm.get(it->first));
          int_list.resize(string_list.size());
          for (unsigned int i=0; i<string_list.size(); ++i)
            {
              std::istringstream reader(string_list[i]);
              reader >> int_list[i];// = std::stoul(string_list[i]);
            }
        }
      else if (it->second.type() == typeid(std::vector<double> *))
        {
          std::vector<double> &double_list = *(boost::any_cast<std::vector<double>*>(it->second));
          double_list = Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
        }
      else if (it->second.type() == typeid(std::vector<std::vector<unsigned int> > *))
        {
          std::vector<std::vector<unsigned int> > &int_table =
            *(boost::any_cast<std::vector<std::vector<unsigned int> >*>(it->second));

          std::vector<std::string> string_list_of_lists = Utilities::split_string_list(prm.get(it->first), ';');
          int_table.resize(string_list_of_lists.size());
          for (unsigned int i=0; i<int_table.size(); ++i)
            {
              std::vector<std::string> string_list = Utilities::split_string_list(string_list_of_lists[i], ',');
              int_table[i].resize(string_list.size());
              for (unsigned int j=0; j<int_table[i].size(); ++j)
                {
                  std::istringstream reader(string_list[j]);
                  reader >> int_table[i][j];
                }
            }
        }
      else
        {
          AssertThrow(false, ExcNotImplemented());
        }
    }
}

void ParameterAcceptor::parse_parameters_call_back() {}

D2K_NAMESPACE_CLOSE

<commit_msg>removed deprecated function<commit_after>//-----------------------------------------------------------
//
//    Copyright (C) 2015 - 2016 by the deal2lkit authors
//
//    This file is part of the deal2lkit library.
//
//    The deal2lkit library is free software; you can use it, redistribute
//    it, and/or modify it under the terms of the GNU Lesser General
//    Public License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//    The full text of the license can be found in the file LICENSE at
//    the top level of the deal2lkit distribution.
//
//-----------------------------------------------------------

#include <deal2lkit/parameter_acceptor.h>
#include <deal2lkit/utilities.h>
#include <deal.II/base/point.h>
#include <deal.II/base/revision.h>
#include <deal2lkit/revision.h>
#include <fstream>

D2K_NAMESPACE_OPEN

// Static empty class list
std::vector<SmartPointer<ParameterAcceptor> > ParameterAcceptor::class_list;
// Static parameter handler
ParameterHandler ParameterAcceptor::prm;

ParameterAcceptor::ParameterAcceptor(const std::string name) :
  acceptor_id(class_list.size()),
  section_name(name)
{
  SmartPointer<ParameterAcceptor> pt(this, type(*this).c_str());
  class_list.push_back(pt);
}

ParameterAcceptor::~ParameterAcceptor()
{
  class_list[acceptor_id] = 0;
}

std::string ParameterAcceptor::get_section_name() const
{
  return (section_name != "" ? section_name : type(*this));
}

void
ParameterAcceptor::initialize(const std::string filename,
                              const std::string out_filename)
{
  prm.clear();
  declare_all_parameters(prm);
  if (filename != "")
    {
      // check the extension of input file
      if (filename.substr(filename.find_last_of(".") + 1) == "prm")
        prm.parse_input(filename);
      else if (filename.substr(filename.find_last_of(".") + 1) == "xml")
        {
          std::ifstream is(filename);
          prm.parse_input_from_xml(is);
        }
      else
        AssertThrow(false, ExcMessage("Invalid extension of parameter file. Please use .prm or .xml"));
    }
  parse_all_parameters(prm);
  if (out_filename != "")
    {
      std::ofstream outfile(out_filename.c_str());
      Assert(outfile, ExcIO());
      std::string extension = out_filename.substr(out_filename.find_last_of(".") + 1);

      if ( extension == "prm")
        {
          outfile << "# Parameter file generated with " << std::endl
                  << "# D2K_GIT_BRANCH=       " << D2K_GIT_BRANCH << std::endl
                  << "# D2K_GIT_SHORTREV=     " << D2K_GIT_SHORTREV << std::endl
                  << "# DEAL_II_GIT_BRANCH=   " << DEAL_II_GIT_BRANCH  << std::endl
                  << "# DEAL_II_GIT_SHORTREV= " << DEAL_II_GIT_SHORTREV << std::endl;
          prm.print_parameters(outfile, ParameterHandler::ShortText);
        }
      else if (extension == "xml")
        prm.print_parameters(outfile, ParameterHandler::XML);
      else if (extension == "latex" || extension == "tex")
        prm.print_parameters(outfile, ParameterHandler::LaTeX);
      else
        AssertThrow(false,ExcNotImplemented());
    }
}

void
ParameterAcceptor::clear()
{
  class_list.clear();
}

void
ParameterAcceptor::log_info()
{
  deallog.push("ParameterAcceptor");
  for (unsigned int i=0; i<class_list.size(); ++i)
    {
      deallog << "Class " << i << ":";
      if (class_list[i])
        deallog << class_list[i]->get_section_name() << std::endl;
      else
        deallog << " NULL" << std::endl;
    }
  deallog.pop();
}

void ParameterAcceptor::parse_all_parameters(ParameterHandler &prm)
{
  std::vector<std::string> old_secs;
  for (unsigned int i=0; i< class_list.size(); ++i)
    if (class_list[i] != NULL)
      {
        std::vector<std::string> secs;
        secs = Utilities::split_string_list(class_list[i]->get_section_name(), sep);
        const unsigned int secs_size = secs.size();

        if (secs_size == 1) // add a subsection with relative path
          {
            // enter the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.enter_subsection(old_secs[s]);

            // enter current subsection
            prm.enter_subsection(secs[0]);

            class_list[i]->parse_parameters(prm);
            class_list[i]->parse_parameters_call_back();

            // leave current subsection
            prm.leave_subsection();

            // leave the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.leave_subsection();

            // the old path is unchanged
          }

        else // we have at least one separator "/"
          {
            if (secs[0]=="") // the section name begins with "/"
              {
                // first of all remove the "empty" section
                secs.erase(secs.begin());

                // this means absolute path so we do not enter
                // the old path
                for (unsigned int s=0; s<secs.size(); ++s)
                  prm.enter_subsection(secs[s]);

                class_list[i]->parse_parameters(prm);
                class_list[i]->parse_parameters_call_back();

                // leave all the current sections
                for (unsigned int s=0; s<secs.size(); ++s)
                  prm.leave_subsection();

                // since we have started from the root section i.e. "/"
                // we need to set the old path to the current one
                // without the last subsection

                // remove the last subsection
                secs.pop_back();

                // update the old path
                old_secs.swap(secs);

              }
            else // append the path to the old path
              {
                // enter the old path
                for (unsigned int s=0; s<old_secs.size(); ++s)
                  prm.enter_subsection(old_secs[s]);

                // new path
                for (unsigned int s=0; s<secs.size(); ++s)
                  prm.enter_subsection(secs[s]);

                class_list[i]->parse_parameters(prm);
                class_list[i]->parse_parameters_call_back();

                // leave all subsections
                for (unsigned int s=0; s<(secs.size()+old_secs.size()); ++s)
                  prm.leave_subsection();

                // we need now to append the secs path (without the last subsection)
                // to the old path

                // remove last subsection
                secs.pop_back();

                // append secs to old_secs
                old_secs.insert(old_secs.begin(), secs.begin(), secs.end());

              }
          }
      }
}

void ParameterAcceptor::declare_all_parameters(ParameterHandler &prm)
{
  std::vector<std::string> old_secs;
  for (unsigned int i=0; i< class_list.size(); ++i)
    if (class_list[i] != NULL)
      {
        std::vector<std::string> secs;
        secs = Utilities::split_string_list(class_list[i]->get_section_name(), sep);
        const unsigned int secs_size = secs.size();

        if (secs_size == 1) // add a subsection with relative path
          {
            // enter the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.enter_subsection(old_secs[s]);

            // enter current subsection
            prm.enter_subsection(secs[0]);

            class_list[i]->declare_parameters(prm);

            // leave current subsection
            prm.leave_subsection();

            // leave the old path
            for (unsigned int s=0; s<old_secs.size(); ++s)
              prm.leave_subsection();

            // the old path is unchanged
          }

        else // we have at least one separator "/"
          {
            for (unsigned int s=0; s <secs.size(); ++s)
              if (secs[0]=="") // the section name begins with "/"
                {
                  // first of all remove the "empty" section
                  secs.erase(secs.begin());

                  // this means absolute path so we do not enter
                  // the old path
                  for (unsigned int s=0; s<secs.size(); ++s)
                    prm.enter_subsection(secs[s]);

                  class_list[i]->declare_parameters(prm);

                  // leave all the current sections
                  for (unsigned int s=0; s<secs.size(); ++s)
                    prm.leave_subsection();

                  // since we have started from the root section i.e. "/"
                  // we need to set the old path to the current one
                  // without the last subsection

                  // remove the last subsection
                  secs.pop_back();

                  // update the old path
                  old_secs.swap(secs);

                }
              else // append the path to the old path
                {
                  // enter the old path
                  for (unsigned int s=0; s<old_secs.size(); ++s)
                    prm.enter_subsection(old_secs[s]);

                  // new path
                  for (unsigned int s=0; s<secs.size(); ++s)
                    prm.enter_subsection(secs[s]);

                  class_list[i]->declare_parameters(prm);

                  // leave all subsections
                  for (unsigned int s=0; s<(secs.size()+old_secs.size()); ++s)
                    prm.leave_subsection();

                  // we need now to append the secs path (without the last subsection)
                  // to the old path

                  // remove last subsection
                  secs.pop_back();

                  // append secs to old_secs
                  old_secs.insert(old_secs.begin(), secs.begin(), secs.end());

                }
          }
      }
}

void ParameterAcceptor::parse_parameters(ParameterHandler &prm)
{
  for (auto it = parameters.begin(); it != parameters.end(); ++it)
    {
      if (it->second.type() == typeid(std::string *))
        {
          *(boost::any_cast<std::string *>(it->second)) = prm.get(it->first);
        }
      else if (it->second.type() == typeid(double *))
        {
          *(boost::any_cast<double *>(it->second)) = prm.get_double(it->first);
        }
      else if (it->second.type() == typeid(int *))
        {
          *(boost::any_cast<int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(unsigned int *))
        {
          *(boost::any_cast<unsigned int *>(it->second)) = prm.get_integer(it->first);
        }
      else if (it->second.type() == typeid(bool *))
        {
          *(boost::any_cast<bool *>(it->second)) = prm.get_bool(it->first);
        }
      // Here we have the difficult types...
      // First all point types.
      else if (it->second.type() == typeid(Point<1> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 1);

          Point<1> &pp = *(boost::any_cast<Point<1>*>(it->second));
          pp[0] = p[0];
        }
      else if (it->second.type() == typeid(Point<2> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 2);

          Point<2> &pp = *(boost::any_cast<Point<2>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
        }
      else if (it->second.type() == typeid(Point<3> *))
        {
          std::vector<double> p =
            Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
          AssertDimension(p.size(), 3);

          Point<3> &pp = *(boost::any_cast<Point<3>*>(it->second));
          pp[0] = p[0];
          pp[1] = p[1];
          pp[2] = p[2];
        }
      else if (it->second.type() == typeid(std::vector<std::string> *))
        {
          std::vector<std::string> &string_list = *(boost::any_cast<std::vector<std::string>*>(it->second));
          string_list = Utilities::split_string_list(prm.get(it->first));
        }
      else if (it->second.type() == typeid(std::vector<unsigned int> *))
        {
          std::vector<unsigned int> &int_list = *(boost::any_cast<std::vector<unsigned int>*>(it->second));
          std::vector<std::string> string_list = Utilities::split_string_list(prm.get(it->first));
          int_list.resize(string_list.size());
          for (unsigned int i=0; i<string_list.size(); ++i)
            {
              std::istringstream reader(string_list[i]);
              reader >> int_list[i];// = std::stoul(string_list[i]);
            }
        }
      else if (it->second.type() == typeid(std::vector<double> *))
        {
          std::vector<double> &double_list = *(boost::any_cast<std::vector<double>*>(it->second));
          double_list = Utilities::string_to_double(Utilities::split_string_list(prm.get(it->first)));
        }
      else if (it->second.type() == typeid(std::vector<std::vector<unsigned int> > *))
        {
          std::vector<std::vector<unsigned int> > &int_table =
            *(boost::any_cast<std::vector<std::vector<unsigned int> >*>(it->second));

          std::vector<std::string> string_list_of_lists = Utilities::split_string_list(prm.get(it->first), ';');
          int_table.resize(string_list_of_lists.size());
          for (unsigned int i=0; i<int_table.size(); ++i)
            {
              std::vector<std::string> string_list = Utilities::split_string_list(string_list_of_lists[i], ',');
              int_table[i].resize(string_list.size());
              for (unsigned int j=0; j<int_table[i].size(); ++j)
                {
                  std::istringstream reader(string_list[j]);
                  reader >> int_table[i][j];
                }
            }
        }
      else
        {
          AssertThrow(false, ExcNotImplemented());
        }
    }
}

void ParameterAcceptor::parse_parameters_call_back() {}

D2K_NAMESPACE_CLOSE

<|endoftext|>


<commit_before>#pragma once

#include <cstdlib>
#include <string>

namespace principia {
namespace base {

#define STRINGIFY(X) #X
#define STRINGIFY_EXPANSION(X) STRINGIFY(X)

// See http://goo.gl/2EVxN4 for a partial overview of compiler detection and
// version macros.  We cannot use |COMPILER_MSVC| because it conflicts with
// a macro in the benchmark library, so the macros have obnoxiously long names.
// TODO(phl): See whether that |COMPILER_MSVC| macro can be removed from port.h.
#if defined(_MSC_VER) && defined(__clang__)
#define PRINCIPIA_COMPILER_CLANG_CL 1
char const* const kCompilerName = "Clang-cl";
char const* const kCompilerVersion = __VERSION__;
#elif defined(__clang__)
#define PRINCIPIA_COMPILER_CLANG 1
char const* const kCompilerName = "Clang";
char const* const kCompilerVersion = __VERSION__;
#elif defined(_MSC_VER)
#define PRINCIPIA_COMPILER_MSVC 1
char const* const kCompilerName = "Microsoft Visual C++";
char const* const kCompilerVersion = STRINGIFY_EXPANSION(_MSC_FULL_VER);
#elif defined(__ICC) || defined(__INTEL_COMPILER)
#define PRINCIPIA_COMPILER_ICC 1
char const* const kCompilerName = "Intel C++ Compiler";
char const* const kCompilerVersion = __VERSION__;
#elif defined(__GNUC__)
#define PRINCIPIA_COMPILER_GCC 1
char const* const kCompilerName = "G++";
char const* const kCompilerVersion = __VERSION__;
#else
#error "What is this, Borland C++?"
#endif

#if defined(__APPLE__)
#define OS_MACOSX 1
char const* const kOperatingSystem = "OS X";
#elif defined(__linux__)
#define OS_LINUX 1
char const* const kOperatingSystem = "Linux";
#elif defined(__FreeBSD__)
#define OS_FREEBSD 1
char const* const kOperatingSystem = "FreeBSD";
#elif defined(_WIN32)
#define OS_WIN 1
char const* const kOperatingSystem = "Windows";
#else
#error "Try OS/360."
#endif

#if defined(__i386) || defined(_M_IX86)
#define ARCH_CPU_X86_FAMILY 1
#define ARCH_CPU_X86 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
char const* const kArchitecture = "x86";
#elif defined(_M_X64) || defined(__x86_64__)
#define ARCH_CPU_X86_FAMILY 1
#define ARCH_CPU_X86_64 1
#define ARCH_CPU_64_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
char const* const kArchitecture = "x86-64";
#else
#error "Have you tried a Cray-1?"
#endif

#if defined(CDECL)
#  error "CDECL already defined"
#else
// Architecture macros from http://goo.gl/ZypnO8.
// We use cdecl on x86, the calling convention is unambiguous on x86-64.
#  if ARCH_CPU_X86
#    if PRINCIPIA_COMPILER_CLANG ||  \
        PRINCIPIA_COMPILER_MSVC ||   \
        PRINCIPIA_COMPILER_CLANG_CL
#      define CDECL __cdecl
#    elif PRINCIPIA_COMPILER_ICC || PRINCIPIA_COMPILER_GCC
#      define CDECL __attribute__((cdecl))
#    else
#      error "Get a real compiler!"
#    endif
#  elif ARCH_CPU_X86_64
#    define CDECL
#  else
#    error "Have you tried a Cray-1?"
#  endif
#endif

// DLL-exported functions for interfacing with Platform Invocation Services.
#if defined(PRINCIPIA_DLL)
#  error "PRINCIPIA_DLL already defined"
#else
#  if OS_WIN
#    if PRINCIPIA_DLL_IMPORT
#      define PRINCIPIA_DLL __declspec(dllimport)
#    else
#      define PRINCIPIA_DLL __declspec(dllexport)
#    endif
#  else
#    define PRINCIPIA_DLL __attribute__((visibility("default")))
#  endif
#endif

// A function for use on control paths that don't return a value, typically
// because they end with a |LOG(FATAL)|.
#if PRINCIPIA_COMPILER_CLANG || PRINCIPIA_COMPILER_CLANG_CL
[[noreturn]]
#elif PRINCIPIA_COMPILER_MSVC
__declspec(noreturn)
#elif PRINCIPIA_COMPILER_ICC
__attribute__((noreturn))
#else
#error "What compiler is this?"
#endif
inline void noreturn() { std::exit(0); }

// Used to force inlining.
#if PRINCIPIA_COMPILER_CLANG    ||  \
    PRINCIPIA_COMPILER_CLANG_CL ||  \
    PRINCIPIA_COMPILER_GCC
#  define FORCE_INLINE [[gnu::always_inline]]  // NOLINT(whitespace/braces)
#elif PRINCIPIA_COMPILER_MSVC
#  define FORCE_INLINE __forceinline
#elif PRINCIPIA_COMPILER_ICC
#  define FORCE_INLINE __attribute__((always_inline))
#else
#  error "What compiler is this?"
#endif

// Used to emit the function signature.
#if PRINCIPIA_COMPILER_CLANG    ||  \
    PRINCIPIA_COMPILER_CLANG_CL ||  \
    PRINCIPIA_COMPILER_GCC
#  define FUNCTION_SIGNATURE __PRETTY_FUNCTION__
#elif PRINCIPIA_COMPILER_MSVC
#  define FUNCTION_SIGNATURE __FUNCSIG__
#else
#  error "What compiler is this?"
#endif

// Thread-safety analysis.
#if PRINCIPIA_COMPILER_CLANG || PRINCIPIA_COMPILER_CLANG_CL
#  define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#  define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#else
#  define GUARDED_BY(x)
#endif

#define VLOG_AND_RETURN(verboselevel, expression)                  \
  do {                                                             \
    auto const& value__ = (expression);                            \
    VLOG(verboselevel) << __FUNCTION__ << " returns " << value__;  \
    return value__;                                                \
  } while (false)

#define NAMED(expression) #expression << ": " << (expression)

// We preserve issue #228 in Bourbaki because we don't have trajectory
// decimation yet.
#define WE_LOVE_228

}  // namespace base
}  // namespace principia
<commit_msg>Fix for linux FORCE_INLINE macro<commit_after>#pragma once

#include <cstdlib>
#include <string>

namespace principia {
namespace base {

#define STRINGIFY(X) #X
#define STRINGIFY_EXPANSION(X) STRINGIFY(X)

// See http://goo.gl/2EVxN4 for a partial overview of compiler detection and
// version macros.  We cannot use |COMPILER_MSVC| because it conflicts with
// a macro in the benchmark library, so the macros have obnoxiously long names.
// TODO(phl): See whether that |COMPILER_MSVC| macro can be removed from port.h.
#if defined(_MSC_VER) && defined(__clang__)
#define PRINCIPIA_COMPILER_CLANG_CL 1
char const* const kCompilerName = "Clang-cl";
char const* const kCompilerVersion = __VERSION__;
#elif defined(__clang__)
#define PRINCIPIA_COMPILER_CLANG 1
char const* const kCompilerName = "Clang";
char const* const kCompilerVersion = __VERSION__;
#elif defined(_MSC_VER)
#define PRINCIPIA_COMPILER_MSVC 1
char const* const kCompilerName = "Microsoft Visual C++";
char const* const kCompilerVersion = STRINGIFY_EXPANSION(_MSC_FULL_VER);
#elif defined(__ICC) || defined(__INTEL_COMPILER)
#define PRINCIPIA_COMPILER_ICC 1
char const* const kCompilerName = "Intel C++ Compiler";
char const* const kCompilerVersion = __VERSION__;
#elif defined(__GNUC__)
#define PRINCIPIA_COMPILER_GCC 1
char const* const kCompilerName = "G++";
char const* const kCompilerVersion = __VERSION__;
#else
#error "What is this, Borland C++?"
#endif

#if defined(__APPLE__)
#define OS_MACOSX 1
char const* const kOperatingSystem = "OS X";
#elif defined(__linux__)
#define OS_LINUX 1
char const* const kOperatingSystem = "Linux";
#elif defined(__FreeBSD__)
#define OS_FREEBSD 1
char const* const kOperatingSystem = "FreeBSD";
#elif defined(_WIN32)
#define OS_WIN 1
char const* const kOperatingSystem = "Windows";
#else
#error "Try OS/360."
#endif

#if defined(__i386) || defined(_M_IX86)
#define ARCH_CPU_X86_FAMILY 1
#define ARCH_CPU_X86 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
char const* const kArchitecture = "x86";
#elif defined(_M_X64) || defined(__x86_64__)
#define ARCH_CPU_X86_FAMILY 1
#define ARCH_CPU_X86_64 1
#define ARCH_CPU_64_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
char const* const kArchitecture = "x86-64";
#else
#error "Have you tried a Cray-1?"
#endif

#if defined(CDECL)
#  error "CDECL already defined"
#else
// Architecture macros from http://goo.gl/ZypnO8.
// We use cdecl on x86, the calling convention is unambiguous on x86-64.
#  if ARCH_CPU_X86
#    if PRINCIPIA_COMPILER_CLANG ||  \
        PRINCIPIA_COMPILER_MSVC ||   \
        PRINCIPIA_COMPILER_CLANG_CL
#      define CDECL __cdecl
#    elif PRINCIPIA_COMPILER_ICC || PRINCIPIA_COMPILER_GCC
#      define CDECL __attribute__((cdecl))
#    else
#      error "Get a real compiler!"
#    endif
#  elif ARCH_CPU_X86_64
#    define CDECL
#  else
#    error "Have you tried a Cray-1?"
#  endif
#endif

// DLL-exported functions for interfacing with Platform Invocation Services.
#if defined(PRINCIPIA_DLL)
#  error "PRINCIPIA_DLL already defined"
#else
#  if OS_WIN
#    if PRINCIPIA_DLL_IMPORT
#      define PRINCIPIA_DLL __declspec(dllimport)
#    else
#      define PRINCIPIA_DLL __declspec(dllexport)
#    endif
#  else
#    define PRINCIPIA_DLL __attribute__((visibility("default")))
#  endif
#endif

// A function for use on control paths that don't return a value, typically
// because they end with a |LOG(FATAL)|.
#if PRINCIPIA_COMPILER_CLANG || PRINCIPIA_COMPILER_CLANG_CL
[[noreturn]]
#elif PRINCIPIA_COMPILER_MSVC
__declspec(noreturn)
#elif PRINCIPIA_COMPILER_ICC
__attribute__((noreturn))
#else
#error "What compiler is this?"
#endif
inline void noreturn() { std::exit(0); }

// Used to force inlining.
#if PRINCIPIA_COMPILER_CLANG    ||  \
    PRINCIPIA_COMPILER_CLANG_CL ||  \
    PRINCIPIA_COMPILER_GCC
#  define FORCE_INLINE [[gnu::always_inline]] inline  // NOLINT(whitespace/braces)
#elif PRINCIPIA_COMPILER_MSVC
#  define FORCE_INLINE __forceinline
#elif PRINCIPIA_COMPILER_ICC
#  define FORCE_INLINE __attribute__((always_inline))
#else
#  error "What compiler is this?"
#endif

// Used to emit the function signature.
#if PRINCIPIA_COMPILER_CLANG    ||  \
    PRINCIPIA_COMPILER_CLANG_CL ||  \
    PRINCIPIA_COMPILER_GCC
#  define FUNCTION_SIGNATURE __PRETTY_FUNCTION__
#elif PRINCIPIA_COMPILER_MSVC
#  define FUNCTION_SIGNATURE __FUNCSIG__
#else
#  error "What compiler is this?"
#endif

// Thread-safety analysis.
#if PRINCIPIA_COMPILER_CLANG || PRINCIPIA_COMPILER_CLANG_CL
#  define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#  define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#else
#  define GUARDED_BY(x)
#endif

#define VLOG_AND_RETURN(verboselevel, expression)                  \
  do {                                                             \
    auto const& value__ = (expression);                            \
    VLOG(verboselevel) << __FUNCTION__ << " returns " << value__;  \
    return value__;                                                \
  } while (false)

#define NAMED(expression) #expression << ": " << (expression)

// We preserve issue #228 in Bourbaki because we don't have trajectory
// decimation yet.
#define WE_LOVE_228

}  // namespace base
}  // namespace principia
<|endoftext|>