001package net.gdface.codegen.thrift;
002
003import java.lang.reflect.Type;
004import java.util.ArrayList;
005import java.util.Arrays;
006import java.util.Collections;
007import java.util.List;
008import com.google.common.base.Strings;
009
010import com.google.common.base.Joiner;
011
012import com.google.common.base.MoreObjects;
013import com.google.common.base.Predicate;
014import com.google.common.collect.Iterables;
015import com.google.common.collect.Lists;
016
017import static com.google.common.base.Preconditions.*;
018
019public class CxxHelper {
020
021        public CxxHelper() {
022        }
023        private static ThreadLocal<ArrayList<String>> tlsPackageName=new ThreadLocal<ArrayList<String>>() ;
024        private static ThreadLocal<Boolean> tlsMultiline = new ThreadLocal<Boolean>();
025        private static String getCurrent(String separator){
026                ArrayList<String> pkg = tlsPackageName.get();
027                if(null == pkg){
028                        return "";
029                }
030                return Joiner.on(separator).join(pkg);
031        }
032        public static String getCurrentNamespace(){
033                return getCurrent("::");
034        }
035        public static String getCurrentPackageAsJava(){
036                return getCurrent(".");
037        }
038        public static boolean isCurrentPackage(Class<?> clazz){
039                return null == clazz 
040                                ? false
041                                : clazz.getPackage().getName().equals(getCurrentPackageAsJava());
042        }
043        /**
044         * @param packageName java package或c++ namespace
045         * @param multiline
046         * @return
047         */
048        public static String namespaceBegin(String packageName, boolean multiline){             
049                packageName = MoreObjects.firstNonNull(packageName, "");
050                ArrayList<String> names = Lists.newArrayList(Iterables.filter(Arrays.asList(packageName.split("(\\.|::)")),new Predicate<String>(){
051                        @Override
052                        public boolean apply(String input) {
053                                return !input.trim().isEmpty();
054                        }}));
055                tlsPackageName.set(names);
056                tlsMultiline.set(multiline);
057                StringBuilder builder=new StringBuilder();
058                for(String name:names){
059                        builder.append(String.format("namespace %s{",name));
060                        if(multiline){
061                                builder.append("\n");
062                        }
063                }
064                return builder.toString();
065        }
066        public static String namespaceBegin(Class<?> clazz){
067                return null==clazz ? "// class is null\n" : namespaceBegin(clazz.getPackage().getName(), true);
068        }
069        public static String namespaceBegin(Class<?> clazz,boolean multiline){
070                return null==clazz ? "// class is null\n" : namespaceBegin(clazz.getPackage().getName(), multiline);
071        }
072        public static String namespaceEnd(){
073                List<String> names = MoreObjects.firstNonNull(tlsPackageName.get(),Collections.<String>emptyList());    
074                StringBuilder builder=new StringBuilder();
075                for(String name:Lists.reverse(names)){
076                        builder.append(String.format("} /* namespace %s */",name));
077                }
078                if(Boolean.TRUE.equals(tlsMultiline.get())){
079                        builder.append("\n");
080                }
081                tlsPackageName.remove();
082                tlsMultiline.remove();
083                return builder.toString();              
084        }
085        
086        /**
087         * java 包名或类名转为c++ namespace或类名
088         * @param javaName package或类名
089         * @param isfull 为{@code false}返回空串,{@code javaName}为类名时必须为{@code true},否则无法返回正确结果
090         * @return
091         */
092        public static String cxxNamespace(String javaName,boolean isfull){
093                if(null==javaName || !isfull){
094                        return "";
095                }
096                // . $ 都替换为 ::
097                return javaName.replaceAll("[\\.\\$]", "::");
098        }
099        public static String cxxNamespace(Class<?>clazz,boolean isfull ){
100                return null==clazz ? "// class is null\n" :  cxxNamespace(clazz.getPackage().getName(),isfull);
101        }
102        public static String cxxNamespace(String packageName){
103                return cxxNamespace(packageName,true);
104        }
105
106        public static String cxxNamespace(Class<?>clazz){
107                return cxxNamespace(clazz,true);
108        }
109        public static String cxxClassName(Class<?>clazz,boolean isfull ){
110                if(null==clazz){
111                        return "";
112                }
113                if(isfull){
114                        return cxxNamespace(clazz.getPackage().getName() + "." + clazz.getSimpleName(),true) ;
115                }
116                return clazz.getSimpleName();
117        }
118
119        public static String cxxClassName(Class<?>clazz){
120                return getTypeName(cxxClassName(clazz,true));
121        }
122        /**
123         * 返回一个c++类名的简单类名,类似 {@link Class#getSimpleName()}
124         * @param cxxType
125         * @return
126         */
127        public static String simpleName(String cxxType){
128                if(null != cxxType){
129                        return cxxType.replaceAll("^(?:::)?(?:\\w+::)*", "");
130                }
131                return cxxType;
132        }
133        public static String getCxxNamespace(String cxxType){
134                if(null == cxxType){
135                        return "";
136                }
137                return cxxType.replaceAll("::\\w+$", "");
138        }
139        public static String getCxxNamespaceOfJava(String javaClassName){
140                if(null == javaClassName){
141                        return "";
142                }
143                return getCxxNamespace(cxxNamespace(javaClassName,true));
144        }
145        /**
146         * 根据当前namespace返回最简单的类型名
147         * @param cxxType cxx类名
148         * @return
149         */
150        public static String getTypeName(String cxxType){
151                checkArgument((!Strings.isNullOrEmpty(cxxType)) && cxxType.indexOf('.') == -1,
152                                "invalid c++ Type %s",cxxType);
153                String cns = getCurrentNamespace();
154                if(!cns.isEmpty()){
155                        cns = getCurrentNamespace() + "::";
156                }
157                return cxxType.replaceFirst(cns, "");
158        }
159        public CxxType getCxxType(Type type){
160                return CxxType.getThriftType(type);
161        }
162        /**
163         * 判断指定的类型是否需要类型转换
164         * @param type
165         * @return
166         */
167        public boolean needCast(Type type){
168                return CxxType.getThriftType(type).isNeedCast();
169        }
170}