13771902e922796f506dfda5955d7d80b61104696Ted Kremenek//==--- ImmutableList.h - Immutable (functional) list interface --*- C++ -*-==// 23771902e922796f506dfda5955d7d80b61104696Ted Kremenek// 33771902e922796f506dfda5955d7d80b61104696Ted Kremenek// The LLVM Compiler Infrastructure 43771902e922796f506dfda5955d7d80b61104696Ted Kremenek// 53771902e922796f506dfda5955d7d80b61104696Ted Kremenek// This file is distributed under the University of Illinois Open Source 63771902e922796f506dfda5955d7d80b61104696Ted Kremenek// License. See LICENSE.TXT for details. 73771902e922796f506dfda5955d7d80b61104696Ted Kremenek// 83771902e922796f506dfda5955d7d80b61104696Ted Kremenek//===----------------------------------------------------------------------===// 93771902e922796f506dfda5955d7d80b61104696Ted Kremenek// 103771902e922796f506dfda5955d7d80b61104696Ted Kremenek// This file defines the ImmutableList class. 113771902e922796f506dfda5955d7d80b61104696Ted Kremenek// 123771902e922796f506dfda5955d7d80b61104696Ted Kremenek//===----------------------------------------------------------------------===// 133771902e922796f506dfda5955d7d80b61104696Ted Kremenek 143771902e922796f506dfda5955d7d80b61104696Ted Kremenek#ifndef LLVM_ADT_IMLIST_H 153771902e922796f506dfda5955d7d80b61104696Ted Kremenek#define LLVM_ADT_IMLIST_H 163771902e922796f506dfda5955d7d80b61104696Ted Kremenek 173771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include "llvm/Support/Allocator.h" 183771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include "llvm/ADT/FoldingSet.h" 191f6efa3996dd1929fbc129203ce5009b620e6969Michael J. Spencer#include "llvm/Support/DataTypes.h" 203771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include <cassert> 213771902e922796f506dfda5955d7d80b61104696Ted Kremenek 223771902e922796f506dfda5955d7d80b61104696Ted Kremeneknamespace llvm { 233771902e922796f506dfda5955d7d80b61104696Ted Kremenek 243771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T> class ImmutableListFactory; 253a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 263771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T> 273771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableListImpl : public FoldingSetNode { 283771902e922796f506dfda5955d7d80b61104696Ted Kremenek T Head; 29e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek const ImmutableListImpl* Tail; 303771902e922796f506dfda5955d7d80b61104696Ted Kremenek 31e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek ImmutableListImpl(const T& head, const ImmutableListImpl* tail = 0) 323771902e922796f506dfda5955d7d80b61104696Ted Kremenek : Head(head), Tail(tail) {} 333a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 343771902e922796f506dfda5955d7d80b61104696Ted Kremenek friend class ImmutableListFactory<T>; 353a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 363771902e922796f506dfda5955d7d80b61104696Ted Kremenek // Do not implement. 373771902e922796f506dfda5955d7d80b61104696Ted Kremenek void operator=(const ImmutableListImpl&); 383771902e922796f506dfda5955d7d80b61104696Ted Kremenek ImmutableListImpl(const ImmutableListImpl&); 393a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 403771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic: 413771902e922796f506dfda5955d7d80b61104696Ted Kremenek const T& getHead() const { return Head; } 42e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek const ImmutableListImpl* getTail() const { return Tail; } 433a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 443771902e922796f506dfda5955d7d80b61104696Ted Kremenek static inline void Profile(FoldingSetNodeID& ID, const T& H, 45e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek const ImmutableListImpl* L){ 463771902e922796f506dfda5955d7d80b61104696Ted Kremenek ID.AddPointer(L); 473771902e922796f506dfda5955d7d80b61104696Ted Kremenek ID.Add(H); 483771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 493a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 503771902e922796f506dfda5955d7d80b61104696Ted Kremenek void Profile(FoldingSetNodeID& ID) { 513771902e922796f506dfda5955d7d80b61104696Ted Kremenek Profile(ID, Head, Tail); 523771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 533771902e922796f506dfda5955d7d80b61104696Ted Kremenek}; 543a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 553771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// ImmutableList - This class represents an immutable (functional) list. 563771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// It is implemented as a smart pointer (wraps ImmutableListImpl), so it 573771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// it is intended to always be copied by value as if it were a pointer. 583771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// This interface matches ImmutableSet and ImmutableMap. ImmutableList 593771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// objects should almost never be created directly, and instead should 603771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// be created by ImmutableListFactory objects that manage the lifetime 613771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// of a group of lists. When the factory object is reclaimed, all lists 623771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// created by that factory are released as well. 633771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T> 643771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableList { 653771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic: 663771902e922796f506dfda5955d7d80b61104696Ted Kremenek typedef T value_type; 673771902e922796f506dfda5955d7d80b61104696Ted Kremenek typedef ImmutableListFactory<T> Factory; 683771902e922796f506dfda5955d7d80b61104696Ted Kremenek 693771902e922796f506dfda5955d7d80b61104696Ted Kremenekprivate: 70e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek const ImmutableListImpl<T>* X; 713771902e922796f506dfda5955d7d80b61104696Ted Kremenek 723771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic: 733771902e922796f506dfda5955d7d80b61104696Ted Kremenek // This constructor should normally only be called by ImmutableListFactory<T>. 743771902e922796f506dfda5955d7d80b61104696Ted Kremenek // There may be cases, however, when one needs to extract the internal pointer 753771902e922796f506dfda5955d7d80b61104696Ted Kremenek // and reconstruct a list object from that pointer. 76e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek ImmutableList(const ImmutableListImpl<T>* x = 0) : X(x) {} 773771902e922796f506dfda5955d7d80b61104696Ted Kremenek 78e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek const ImmutableListImpl<T>* getInternalPointer() const { 793771902e922796f506dfda5955d7d80b61104696Ted Kremenek return X; 803771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 813a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 823771902e922796f506dfda5955d7d80b61104696Ted Kremenek class iterator { 83e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek const ImmutableListImpl<T>* L; 843771902e922796f506dfda5955d7d80b61104696Ted Kremenek public: 853771902e922796f506dfda5955d7d80b61104696Ted Kremenek iterator() : L(0) {} 863771902e922796f506dfda5955d7d80b61104696Ted Kremenek iterator(ImmutableList l) : L(l.getInternalPointer()) {} 873a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 88445723bfb0d3c4cb7ecebb60710c669cf3dd2c8dTed Kremenek iterator& operator++() { L = L->getTail(); return *this; } 893771902e922796f506dfda5955d7d80b61104696Ted Kremenek bool operator==(const iterator& I) const { return L == I.L; } 90445723bfb0d3c4cb7ecebb60710c669cf3dd2c8dTed Kremenek bool operator!=(const iterator& I) const { return L != I.L; } 913a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman const value_type& operator*() const { return L->getHead(); } 923a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman ImmutableList getList() const { return L; } 933771902e922796f506dfda5955d7d80b61104696Ted Kremenek }; 943771902e922796f506dfda5955d7d80b61104696Ted Kremenek 9530389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// begin - Returns an iterator referring to the head of the list, or 9630389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// an iterator denoting the end of the list if the list is empty. 973771902e922796f506dfda5955d7d80b61104696Ted Kremenek iterator begin() const { return iterator(X); } 983a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 9930389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// end - Returns an iterator denoting the end of the list. This iterator 10030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// does not refer to a valid list element. 1013771902e922796f506dfda5955d7d80b61104696Ted Kremenek iterator end() const { return iterator(); } 1023771902e922796f506dfda5955d7d80b61104696Ted Kremenek 10330389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// isEmpty - Returns true if the list is empty. 1043771902e922796f506dfda5955d7d80b61104696Ted Kremenek bool isEmpty() const { return !X; } 1053a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 106298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky bool contains(const T& V) const { 107298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky for (iterator I = begin(), E = end(); I != E; ++I) { 108298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky if (*I == V) 109298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky return true; 110298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky } 111298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky return false; 112298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky } 113298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky 11430389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// isEqual - Returns true if two lists are equal. Because all lists created 11530389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// from the same ImmutableListFactory are uniqued, this has O(1) complexity 11630389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// because it the contents of the list do not need to be compared. Note 11730389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// that you should only compare two lists created from the same 11830389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// ImmutableListFactory. 1193a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman bool isEqual(const ImmutableList& L) const { return X == L.X; } 12030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek 1213771902e922796f506dfda5955d7d80b61104696Ted Kremenek bool operator==(const ImmutableList& L) const { return isEqual(L); } 1223771902e922796f506dfda5955d7d80b61104696Ted Kremenek 12330389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// getHead - Returns the head of the list. 1243771902e922796f506dfda5955d7d80b61104696Ted Kremenek const T& getHead() { 1253771902e922796f506dfda5955d7d80b61104696Ted Kremenek assert (!isEmpty() && "Cannot get the head of an empty list."); 1263771902e922796f506dfda5955d7d80b61104696Ted Kremenek return X->getHead(); 1273771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 1283a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 12930389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// getTail - Returns the tail of the list, which is another (possibly empty) 13030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek /// ImmutableList. 1313771902e922796f506dfda5955d7d80b61104696Ted Kremenek ImmutableList getTail() { 1323771902e922796f506dfda5955d7d80b61104696Ted Kremenek return X ? X->getTail() : 0; 1333a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman } 1342ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu 1352ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu void Profile(FoldingSetNodeID& ID) const { 1362ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu ID.AddPointer(X); 1372ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu } 1383771902e922796f506dfda5955d7d80b61104696Ted Kremenek}; 1393a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1403771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T> 1413771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableListFactory { 1423a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman typedef ImmutableListImpl<T> ListTy; 1433771902e922796f506dfda5955d7d80b61104696Ted Kremenek typedef FoldingSet<ListTy> CacheTy; 1443a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1453771902e922796f506dfda5955d7d80b61104696Ted Kremenek CacheTy Cache; 1463771902e922796f506dfda5955d7d80b61104696Ted Kremenek uintptr_t Allocator; 1473a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1483771902e922796f506dfda5955d7d80b61104696Ted Kremenek bool ownsAllocator() const { 1493771902e922796f506dfda5955d7d80b61104696Ted Kremenek return Allocator & 0x1 ? false : true; 1503771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 1513a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1523a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman BumpPtrAllocator& getAllocator() const { 1533771902e922796f506dfda5955d7d80b61104696Ted Kremenek return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1); 1543a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman } 1553771902e922796f506dfda5955d7d80b61104696Ted Kremenek 1563771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic: 1573771902e922796f506dfda5955d7d80b61104696Ted Kremenek ImmutableListFactory() 1583771902e922796f506dfda5955d7d80b61104696Ted Kremenek : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {} 1593a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1603771902e922796f506dfda5955d7d80b61104696Ted Kremenek ImmutableListFactory(BumpPtrAllocator& Alloc) 1613771902e922796f506dfda5955d7d80b61104696Ted Kremenek : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {} 1623a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1633771902e922796f506dfda5955d7d80b61104696Ted Kremenek ~ImmutableListFactory() { 1643771902e922796f506dfda5955d7d80b61104696Ted Kremenek if (ownsAllocator()) delete &getAllocator(); 1653771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 1663a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1679c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek ImmutableList<T> concat(const T& Head, ImmutableList<T> Tail) { 1683771902e922796f506dfda5955d7d80b61104696Ted Kremenek // Profile the new list to see if it already exists in our cache. 1693771902e922796f506dfda5955d7d80b61104696Ted Kremenek FoldingSetNodeID ID; 1703771902e922796f506dfda5955d7d80b61104696Ted Kremenek void* InsertPos; 1713a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 172e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek const ListTy* TailImpl = Tail.getInternalPointer(); 1733771902e922796f506dfda5955d7d80b61104696Ted Kremenek ListTy::Profile(ID, Head, TailImpl); 1743771902e922796f506dfda5955d7d80b61104696Ted Kremenek ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos); 1753a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1763771902e922796f506dfda5955d7d80b61104696Ted Kremenek if (!L) { 1773771902e922796f506dfda5955d7d80b61104696Ted Kremenek // The list does not exist in our cache. Create it. 1783771902e922796f506dfda5955d7d80b61104696Ted Kremenek BumpPtrAllocator& A = getAllocator(); 1793771902e922796f506dfda5955d7d80b61104696Ted Kremenek L = (ListTy*) A.Allocate<ListTy>(); 1803771902e922796f506dfda5955d7d80b61104696Ted Kremenek new (L) ListTy(Head, TailImpl); 1813a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1823771902e922796f506dfda5955d7d80b61104696Ted Kremenek // Insert the new list into the cache. 1833771902e922796f506dfda5955d7d80b61104696Ted Kremenek Cache.InsertNode(L, InsertPos); 1843771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 1853a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1863771902e922796f506dfda5955d7d80b61104696Ted Kremenek return L; 1873771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 1883a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1899c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek ImmutableList<T> add(const T& D, ImmutableList<T> L) { 1909c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek return concat(D, L); 1913771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 1923a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1939c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek ImmutableList<T> getEmptyList() const { 1943771902e922796f506dfda5955d7d80b61104696Ted Kremenek return ImmutableList<T>(0); 1953771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 1963a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 1979c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek ImmutableList<T> create(const T& X) { 1989c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek return Concat(X, getEmptyList()); 1993771902e922796f506dfda5955d7d80b61104696Ted Kremenek } 2003771902e922796f506dfda5955d7d80b61104696Ted Kremenek}; 2013a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 2022c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu//===----------------------------------------------------------------------===// 203eca64f0980e3f686a36007c53272780119635337Ted Kremenek// Partially-specialized Traits. 2042c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu//===----------------------------------------------------------------------===// 2052c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu 206eca64f0980e3f686a36007c53272780119635337Ted Kremenektemplate<typename T> struct DenseMapInfo; 207eca64f0980e3f686a36007c53272780119635337Ted Kremenektemplate<typename T> struct DenseMapInfo<ImmutableList<T> > { 208eca64f0980e3f686a36007c53272780119635337Ted Kremenek static inline ImmutableList<T> getEmptyKey() { 209eca64f0980e3f686a36007c53272780119635337Ted Kremenek return reinterpret_cast<ImmutableListImpl<T>*>(-1); 210eca64f0980e3f686a36007c53272780119635337Ted Kremenek } 211eca64f0980e3f686a36007c53272780119635337Ted Kremenek static inline ImmutableList<T> getTombstoneKey() { 212eca64f0980e3f686a36007c53272780119635337Ted Kremenek return reinterpret_cast<ImmutableListImpl<T>*>(-2); 213eca64f0980e3f686a36007c53272780119635337Ted Kremenek } 214eca64f0980e3f686a36007c53272780119635337Ted Kremenek static unsigned getHashValue(ImmutableList<T> X) { 215eca64f0980e3f686a36007c53272780119635337Ted Kremenek uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer()); 2163a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman return (unsigned((uintptr_t)PtrVal) >> 4) ^ 217eca64f0980e3f686a36007c53272780119635337Ted Kremenek (unsigned((uintptr_t)PtrVal) >> 9); 218eca64f0980e3f686a36007c53272780119635337Ted Kremenek } 219eca64f0980e3f686a36007c53272780119635337Ted Kremenek static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) { 220eca64f0980e3f686a36007c53272780119635337Ted Kremenek return X1 == X2; 221eca64f0980e3f686a36007c53272780119635337Ted Kremenek } 222eca64f0980e3f686a36007c53272780119635337Ted Kremenek}; 2233a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman 2244bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnertemplate <typename T> struct isPodLike; 2254bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnertemplate <typename T> 2264bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnerstruct isPodLike<ImmutableList<T> > { static const bool value = true; }; 2274bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattner 2283771902e922796f506dfda5955d7d80b61104696Ted Kremenek} // end llvm namespace 2293771902e922796f506dfda5955d7d80b61104696Ted Kremenek 2303771902e922796f506dfda5955d7d80b61104696Ted Kremenek#endif 231