// Copyright (C) 2013 Google Inc. // // This file is part of YouCompleteMe. // // YouCompleteMe is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // YouCompleteMe 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with YouCompleteMe. If not, see . #include "TranslationUnitStore.h" #include "TranslationUnit.h" #include "Utils.h" #include "exceptions.h" #include #include #include using boost::lock_guard; using boost::shared_ptr; using boost::make_shared; using boost::mutex; namespace YouCompleteMe { namespace { std::size_t HashForFlags( const std::vector< std::string > &flags ) { return boost::hash< std::vector< std::string > >()( flags ); } } // unnamed namespace TranslationUnitStore::TranslationUnitStore( CXIndex clang_index ) : clang_index_( clang_index ) { } TranslationUnitStore::~TranslationUnitStore() { RemoveAll(); } shared_ptr< TranslationUnit > TranslationUnitStore::GetOrCreate( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ) { bool dont_care; return GetOrCreate( filename, unsaved_files, flags, dont_care ); } shared_ptr< TranslationUnit > TranslationUnitStore::GetOrCreate( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool &translation_unit_created ) { translation_unit_created = false; { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); shared_ptr< TranslationUnit > current_unit = GetNoLock( filename ); if ( current_unit && HashForFlags( flags ) == filename_to_flags_hash_[ filename ] ) { return current_unit; } // We create and store an invalid, sentinel TU so that other threads don't // try to create a TU for the same file while we are trying to create this // TU object. When we are done creating the TU, we will overwrite this value // with the valid object. filename_to_translation_unit_[ filename ] = make_shared< TranslationUnit >(); // We need to store the flags for the sentinel TU so that other threads end // up returning the sentinel TU while the real one is being created. filename_to_flags_hash_[ filename ] = HashForFlags( flags ); } boost::shared_ptr< TranslationUnit > unit; try { unit = boost::make_shared< TranslationUnit >( filename, unsaved_files, flags, clang_index_ ); } catch ( ClangParseError & ) { Remove( filename ); return unit; } { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); filename_to_translation_unit_[ filename ] = unit; // Flags have already been stored. } translation_unit_created = true; return unit; } shared_ptr< TranslationUnit > TranslationUnitStore::Get( const std::string &filename ) { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); return GetNoLock( filename ); } bool TranslationUnitStore::Remove( const std::string &filename ) { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); Erase( filename_to_flags_hash_, filename ); return Erase( filename_to_translation_unit_, filename ); } void TranslationUnitStore::RemoveAll() { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); filename_to_translation_unit_.clear(); filename_to_flags_hash_.clear(); } shared_ptr< TranslationUnit > TranslationUnitStore::GetNoLock( const std::string &filename ) { return FindWithDefault( filename_to_translation_unit_, filename, shared_ptr< TranslationUnit >() ); } } // namespace YouCompleteMe